mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-05-13 19:58:57 +00:00
removing added dirs
Original commit message from CVS: removing added dirs
This commit is contained in:
parent
51b8766072
commit
f1a720a4cb
337 changed files with 200 additions and 27960 deletions
2
common
2
common
|
@ -1 +1 @@
|
|||
Subproject commit 4edc214072fe07d2aade96bc336493425654d7b4
|
||||
Subproject commit d1911d4b3d6267f9cd9dfb68fcef2afe4d098092
|
|
@ -87,6 +87,9 @@ Check out both <ulink url="http://www.cse.ogi.edu/sysl/">OGI's
|
|||
pipeline</ulink> and Microsoft's DirectShow for some background.
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_init ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ as external methods.
|
|||
#GstMemChunk
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### TYPEDEF gst_vgint ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -55,6 +55,9 @@ clock providers in the bin.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstBin ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -84,6 +84,9 @@ Last reviewed on August 12th, 2004 (0.8.5)
|
|||
#GstBufferPool, #GstPad, #GstData
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstBuffer ##### -->
|
||||
<para>
|
||||
The basic structure of a buffer.
|
||||
|
|
|
@ -14,6 +14,9 @@ Structure describing sets of media formats
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### MACRO GST_CAPS_FLAGS_ANY ##### -->
|
||||
<para>
|
||||
Flags that this caps has no specific content, but can contain anything.
|
||||
|
|
|
@ -14,6 +14,9 @@ GstChildProxy
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_child_proxy_get_children_count ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ clock so that the clock is always a good measure of the time in the pipeline.
|
|||
#GstSystemClock
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstClock ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -15,3 +15,6 @@ One would have to add this to the CFLAGS when compiling old code.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ If a subsystem is disabled in GStreamer, a value is defined in
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### MACRO GST_DISABLE_LOADSAVE_REGISTRY ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ You'll get a bitmask of flags with gst_cpu_get_flags().
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstCPUFlags ##### -->
|
||||
<para>
|
||||
Flags that represent cpu capabilities
|
||||
|
|
|
@ -16,6 +16,9 @@ GstData provides refcounting, freeing and copying for its child classes.
|
|||
#GstBuffer, #GstBufferPool, #GstEvent
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### MACRO GST_DATA ##### -->
|
||||
<para>
|
||||
Cast a pointer to a GstData
|
||||
|
|
|
@ -14,6 +14,9 @@ GstElement
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstElement ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ Defines public information about a #GstElement
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstElementDetails ##### -->
|
||||
<para>
|
||||
This struct is used to define public information about the element. It
|
||||
|
|
|
@ -54,6 +54,9 @@ so that the autopluggers can select a plugin more appropriatly
|
|||
#GstElement, #GstPlugin, #GstPluginFeature, #GstPadTemplate.
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstElementFactory ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ Categorized error messages
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstCoreError ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ gst_event_new_flush() creates a new flush event.
|
|||
#GstPad, #GstElement
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstEvent ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ on its own.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### USER_FUNCTION GstFilterFunc ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ formats can be used to perform seeking or conversions/query operations.
|
|||
#GstPad, #GstElement
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstFormat ##### -->
|
||||
<para>
|
||||
Standard predefined formats
|
||||
|
|
|
@ -14,6 +14,9 @@ Pseudo link pads
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstGhostPad ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ Core interface implemented by #GstElements that allows runtime querying of inter
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstImplementsInterface ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ in a pipeline.
|
|||
#GstIndexFactory
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstIndex ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ GstIndexFactory is used to dynamically create GstIndex implementations.
|
|||
#GstIndex
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstIndexFactory ##### -->
|
||||
<para>
|
||||
The GstIndexFactory object
|
||||
|
|
|
@ -68,6 +68,9 @@ categories. These are explained at GST_DEBUG_CATEGORY_INIT().
|
|||
and environment variables that affect the debugging output.
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstDebugLevel ##### -->
|
||||
<para>
|
||||
The level defines the importance of a debugging message. The more important a
|
||||
|
|
|
@ -14,3 +14,6 @@ various portabillity helper macros
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ The GstMemChunk is used to allocate critical resources for #GstBuffer and
|
|||
#GstAtomic, #GstBuffer, #GstEvent, #GstData
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstMemChunk ##### -->
|
||||
<para>
|
||||
The memchunk structure
|
||||
|
|
|
@ -67,6 +67,9 @@ object.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstObject ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -57,6 +57,9 @@ Last reviewed on December 13th, 2002 (0.5.0.1)
|
|||
#GstPadTemplate, #GstElement, #GstEvent
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstPad ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -73,6 +73,9 @@ The following example shows you how to add the padtemplate to an elementfactory:
|
|||
#GstPad, #GstElementFactory
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstPadTemplate ##### -->
|
||||
<para>
|
||||
The padtemplate object.
|
||||
|
|
|
@ -14,6 +14,9 @@ get a pipeline from a text pipeline description
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_parse_error_quark ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ the pipeline, use gst_object_unref() to free its resources.
|
|||
#GstBin
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstPipeline ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ to bring the plugin into memory.
|
|||
#GstPluginFeature, #GstType, #GstAutoplug, #GstElementFactory
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_plugin_error_quark ##### -->
|
||||
<para>
|
||||
Get the error quark
|
||||
|
@ -344,13 +347,12 @@ to get a list of plugins that match certain criteria.
|
|||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_plugin_new ##### -->
|
||||
<!-- ##### FUNCTION gst_plugin_free ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@name:
|
||||
@Returns:
|
||||
@plugin:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_library_load ##### -->
|
||||
|
@ -361,3 +363,4 @@ to get a list of plugins that match certain criteria.
|
|||
@name:
|
||||
@Returns:
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ This is a base class for anything that can be added to a #GstPlugin.
|
|||
#GstPlugin
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstPluginFeature ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ enumerate all registered probes to signal them.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstProbe ##### -->
|
||||
<para>
|
||||
The probe structure
|
||||
|
|
|
@ -15,6 +15,9 @@ Query types can be used to perform queries on pads and elements.
|
|||
#GstPad, #GstElement
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstQueryType ##### -->
|
||||
<para>
|
||||
Standard predefined Query types
|
||||
|
|
|
@ -25,6 +25,9 @@ The queue blocks by default.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstQueue ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,3 +14,6 @@ Real link pads
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ All registries build the #GstRegistryPool.
|
|||
#GstPlugin, #GstPluginFeature
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstRegistry ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ the system.
|
|||
GstRegistry
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_registry_pool_list ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ This is a base class for custom schedulers.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstScheduler ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@ Use gst_scheduler_factory_destroy() to remove the factory from the global list.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstSchedulerFactory ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ Generic structure containing fields of names and values
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstStructure ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ system time.
|
|||
#GstClock
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstSystemClock ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ GstTagList
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### TYPEDEF GstTagList ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ Element interface that allows setting and retrieval of media metadata
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstTagSetter ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ A Thread can act as a toplevel bin as it has its own scheduler.
|
|||
#GstBin, #GstPipeline
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstThread ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ Tracing functionality
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstTrace ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ gsttrashstack
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstTrashStack ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ typefinding subsystem
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstTypeFind ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -67,6 +67,9 @@ the given data. You can get quite a bit more complicated than that though.
|
|||
<link linkend="gstreamer-Writing-typefind-functions">Writing typefind functions</link>
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstTypeFindFactory ##### -->
|
||||
<para>
|
||||
Object that stores information about a typefind function
|
||||
|
|
|
@ -14,6 +14,9 @@ various global enums and constants
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstElementState ##### -->
|
||||
<para>
|
||||
These contants describe the state a #GstElement is in and transition scheduled for the #GstElement (the pending state).
|
||||
|
|
|
@ -15,6 +15,9 @@ and the element property that can handle a given URI.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstURIHandler ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ describes URI types
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstURIType ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ various utility functions
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_util_set_value_from_string ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ GValue implementations specific to GStreamer
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### MACRO GST_MAKE_FOURCC ##### -->
|
||||
<para>
|
||||
will transform four characters into a host-endiannness guint32 fourcc:
|
||||
|
|
|
@ -15,6 +15,9 @@ The version macros get defined by including "gst/gst.h".
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### MACRO GST_VERSION_MAJOR ##### -->
|
||||
<para>
|
||||
The major version of GStreamer at compile time
|
||||
|
|
|
@ -14,6 +14,9 @@ XML save/restore operations of pipelines
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstXML ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ exposes a stream interface on pads.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstByteStream ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@ The next step is to get hold of the GstDParamManager instance of a GstElement.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_control_init ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ network connections also need a protocol to do this.
|
|||
#GstBuffer, #GstCaps, #GstEvent
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### ENUM GstDPHeaderFlag ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ dynamic parameter instance
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstDParam ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ linear interpolation dynamic parameter
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstDParamLinInterp ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ are for applications that use elements with dparams.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstDParamManager ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ realtime smoothed dynamic parameter
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstDParamSmooth ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ accelerated routines for getting bits from a data stream.
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT gst_getbits_t ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ conversion between units of measurement
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### STRUCT GstUnitConvert ##### -->
|
||||
<para>
|
||||
|
||||
|
|
11
plugins/elements/.gitignore
vendored
11
plugins/elements/.gitignore
vendored
|
@ -1,11 +0,0 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
||||
*.bb
|
||||
*.bbg
|
||||
*.da
|
||||
*.def
|
|
@ -1,72 +0,0 @@
|
|||
# FIXME:
|
||||
# need to get gstbufferstore.[ch] into its own lib, preferrably
|
||||
# libs/gst/buifferstore
|
||||
# This requires building libs/gst before this dir, which we currently don't
|
||||
# do.
|
||||
|
||||
plugin_LTLIBRARIES = libgstelements.la
|
||||
AS_LIBTOOL_LIB = libgstelements
|
||||
|
||||
EXTRA_DIST = $(as_libtool_EXTRA_DIST)
|
||||
noinst_DATA = $(as_libtool_noinst_DATA_files)
|
||||
|
||||
# FIXME:
|
||||
# Disable multifilesrc on Windows, cause it uses mmap excessively
|
||||
# and I don't feel like fixing it yet. See also the disablement
|
||||
# in gstelements.c.
|
||||
if AS_LIBTOOL_WIN32
|
||||
multifilesrc =
|
||||
pipefilter =
|
||||
else
|
||||
multifilesrc = gstmultifilesrc.c
|
||||
pipefilter = gstpipefilter.c
|
||||
endif
|
||||
|
||||
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||
libgstelements_la_SOURCES = \
|
||||
gstaggregator.c \
|
||||
gstbufferstore.c \
|
||||
gstelements.c \
|
||||
gstfakesink.c \
|
||||
gstfakesrc.c \
|
||||
gstfilesink.c \
|
||||
gstfilesrc.c \
|
||||
gstfdsink.c \
|
||||
gstfdsrc.c \
|
||||
gstidentity.c \
|
||||
gstmd5sink.c \
|
||||
$(multifilesrc) \
|
||||
$(pipefilter) \
|
||||
gstshaper.c \
|
||||
gststatistics.c \
|
||||
gsttee.c \
|
||||
gsttypefindelement.c
|
||||
|
||||
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstelements_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstaggregator.h \
|
||||
gstbufferstore.h \
|
||||
gstfakesink.h \
|
||||
gstfakesrc.h \
|
||||
gstfdsink.h \
|
||||
gstfdsrc.h \
|
||||
gstfilesink.h \
|
||||
gstfilesrc.h \
|
||||
gstidentity.h \
|
||||
gstmd5sink.h \
|
||||
gstmultifilesrc.h \
|
||||
gstpipefilter.h \
|
||||
gstshaper.h \
|
||||
gststatistics.h \
|
||||
gsttee.h \
|
||||
gsttypefindelement.h
|
||||
|
||||
install-data-local: as-libtool-install-data-local
|
||||
|
||||
uninstall-local: as-libtool-uninstall-local
|
||||
|
||||
include $(top_srcdir)/common/as-libtool.mak
|
||||
|
|
@ -1,378 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
*
|
||||
* gstaggregator.c: Aggregator element, N in 1 out
|
||||
*
|
||||
* 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 "gstaggregator.h"
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_aggregator_debug);
|
||||
#define GST_CAT_DEFAULT gst_aggregator_debug
|
||||
|
||||
GstElementDetails gst_aggregator_details =
|
||||
GST_ELEMENT_DETAILS ("Aggregator pipe fitting",
|
||||
"Generic",
|
||||
"N-to-1 pipe fitting",
|
||||
"Wim Taymans <wim.taymans@chello.be>");
|
||||
|
||||
/* Aggregator signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_NUM_PADS,
|
||||
ARG_SILENT,
|
||||
ARG_SCHED,
|
||||
ARG_LAST_MESSAGE
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
GstStaticPadTemplate aggregator_src_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink%d",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define GST_TYPE_AGGREGATOR_SCHED (gst_aggregator_sched_get_type())
|
||||
static GType
|
||||
gst_aggregator_sched_get_type (void)
|
||||
{
|
||||
static GType aggregator_sched_type = 0;
|
||||
static GEnumValue aggregator_sched[] = {
|
||||
{AGGREGATOR_LOOP, "1", "Loop Based"},
|
||||
{AGGREGATOR_LOOP_SELECT, "3", "Loop Based Select"},
|
||||
{AGGREGATOR_CHAIN, "4", "Chain Based"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!aggregator_sched_type) {
|
||||
aggregator_sched_type =
|
||||
g_enum_register_static ("GstAggregatorSched", aggregator_sched);
|
||||
}
|
||||
return aggregator_sched_type;
|
||||
}
|
||||
|
||||
#define AGGREGATOR_IS_LOOP_BASED(ag) ((ag)->sched != AGGREGATOR_CHAIN)
|
||||
|
||||
static GstPad *gst_aggregator_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * temp, const gchar * unused);
|
||||
static void gst_aggregator_update_functions (GstAggregator * aggregator);
|
||||
|
||||
static void gst_aggregator_finalize (GObject * object);
|
||||
static void gst_aggregator_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_aggregator_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_aggregator_chain (GstPad * pad, GstData * _data);
|
||||
static void gst_aggregator_loop (GstElement * element);
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstAggregator, gst_aggregator, GstElement,
|
||||
GST_TYPE_ELEMENT, _do_init);
|
||||
|
||||
static void
|
||||
gst_aggregator_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 (&aggregator_src_template));
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&srctemplate));
|
||||
gst_element_class_set_details (gstelement_class, &gst_aggregator_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_finalize (GObject * object)
|
||||
{
|
||||
GstAggregator *aggregator;
|
||||
|
||||
aggregator = GST_AGGREGATOR (object);
|
||||
|
||||
g_list_free (aggregator->sinkpads);
|
||||
g_free (aggregator->last_message);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_class_init (GstAggregatorClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
|
||||
g_param_spec_int ("num_pads", "Num pads", "The number of source pads",
|
||||
0, G_MAXINT, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "Silent", "Don't produce messages",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCHED,
|
||||
g_param_spec_enum ("sched", "Scheduling",
|
||||
"The type of scheduling this element should use",
|
||||
GST_TYPE_AGGREGATOR_SCHED, AGGREGATOR_CHAIN, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "Last message",
|
||||
"The current state of the element", NULL, G_PARAM_READABLE));
|
||||
|
||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_aggregator_finalize);
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_aggregator_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_aggregator_get_property);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_aggregator_request_new_pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_init (GstAggregator * aggregator)
|
||||
{
|
||||
aggregator->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_pad_set_getcaps_function (aggregator->srcpad, gst_pad_proxy_getcaps);
|
||||
gst_element_add_pad (GST_ELEMENT (aggregator), aggregator->srcpad);
|
||||
|
||||
aggregator->numsinkpads = 0;
|
||||
aggregator->sinkpads = NULL;
|
||||
aggregator->silent = FALSE;
|
||||
aggregator->sched = AGGREGATOR_LOOP;
|
||||
aggregator->last_message = NULL;
|
||||
|
||||
gst_aggregator_update_functions (aggregator);
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_aggregator_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
gchar *name;
|
||||
GstPad *sinkpad;
|
||||
GstAggregator *aggregator;
|
||||
|
||||
g_return_val_if_fail (GST_IS_AGGREGATOR (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SINK) {
|
||||
g_warning ("gstaggregator: request new pad that is not a sink pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aggregator = GST_AGGREGATOR (element);
|
||||
|
||||
name = g_strdup_printf ("sink%d", aggregator->numsinkpads);
|
||||
|
||||
sinkpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
|
||||
if (!AGGREGATOR_IS_LOOP_BASED (aggregator)) {
|
||||
gst_pad_set_chain_function (sinkpad, gst_aggregator_chain);
|
||||
}
|
||||
gst_pad_set_getcaps_function (sinkpad, gst_pad_proxy_getcaps);
|
||||
gst_element_add_pad (GST_ELEMENT (aggregator), sinkpad);
|
||||
|
||||
aggregator->sinkpads = g_list_prepend (aggregator->sinkpads, sinkpad);
|
||||
aggregator->numsinkpads++;
|
||||
|
||||
return sinkpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_update_functions (GstAggregator * aggregator)
|
||||
{
|
||||
GList *pads;
|
||||
|
||||
if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
|
||||
gst_element_set_loop_function (GST_ELEMENT (aggregator),
|
||||
GST_DEBUG_FUNCPTR (gst_aggregator_loop));
|
||||
} else {
|
||||
gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
|
||||
}
|
||||
|
||||
pads = aggregator->sinkpads;
|
||||
while (pads) {
|
||||
GstPad *pad = GST_PAD (pads->data);
|
||||
|
||||
if (AGGREGATOR_IS_LOOP_BASED (aggregator)) {
|
||||
gst_pad_set_get_function (pad, NULL);
|
||||
} else {
|
||||
gst_element_set_loop_function (GST_ELEMENT (aggregator), NULL);
|
||||
}
|
||||
pads = g_list_next (pads);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstAggregator *aggregator;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_AGGREGATOR (object));
|
||||
|
||||
aggregator = GST_AGGREGATOR (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_SILENT:
|
||||
aggregator->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_SCHED:
|
||||
aggregator->sched = g_value_get_enum (value);
|
||||
gst_aggregator_update_functions (aggregator);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstAggregator *aggregator;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_AGGREGATOR (object));
|
||||
|
||||
aggregator = GST_AGGREGATOR (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_PADS:
|
||||
g_value_set_int (value, aggregator->numsinkpads);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, aggregator->silent);
|
||||
break;
|
||||
case ARG_SCHED:
|
||||
g_value_set_enum (value, aggregator->sched);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
g_value_set_string (value, aggregator->last_message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_push (GstAggregator * aggregator, GstPad * pad, GstBuffer * buf,
|
||||
guchar * debug)
|
||||
{
|
||||
if (!aggregator->silent) {
|
||||
g_free (aggregator->last_message);
|
||||
|
||||
aggregator->last_message =
|
||||
g_strdup_printf ("%10.10s ******* (%s:%s)a (%d bytes, %"
|
||||
G_GUINT64_FORMAT ")", debug, GST_DEBUG_PAD_NAME (pad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
|
||||
|
||||
g_object_notify (G_OBJECT (aggregator), "last_message");
|
||||
}
|
||||
|
||||
gst_pad_push (aggregator->srcpad, GST_DATA (buf));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_aggregator_loop (GstElement * element)
|
||||
{
|
||||
GstAggregator *aggregator;
|
||||
GstBuffer *buf;
|
||||
guchar *debug;
|
||||
|
||||
aggregator = GST_AGGREGATOR (element);
|
||||
|
||||
if (aggregator->sched == AGGREGATOR_LOOP) {
|
||||
GList *pads = aggregator->sinkpads;
|
||||
|
||||
/* we'll loop over all pads and try to pull from all
|
||||
* active ones */
|
||||
while (pads) {
|
||||
GstPad *pad = GST_PAD (pads->data);
|
||||
|
||||
pads = g_list_next (pads);
|
||||
|
||||
/* we need to check is the pad is usable. IS_USABLE will check
|
||||
* if the pad is linked, if it is enabled (the element is
|
||||
* playing and the app didn't gst_pad_set_enabled (pad, FALSE))
|
||||
* and that the peer pad is also enabled.
|
||||
*/
|
||||
if (GST_PAD_IS_USABLE (pad)) {
|
||||
buf = GST_BUFFER (gst_pad_pull (pad));
|
||||
debug = (guchar *) "loop";
|
||||
|
||||
/* then push it forward */
|
||||
gst_aggregator_push (aggregator, pad, buf, debug);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (aggregator->sched == AGGREGATOR_LOOP_SELECT) {
|
||||
GstPad *pad;
|
||||
|
||||
debug = (guchar *) "loop_select";
|
||||
|
||||
buf = GST_BUFFER (gst_pad_collectv (&pad, aggregator->sinkpads));
|
||||
|
||||
gst_aggregator_push (aggregator, pad, buf, debug);
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_aggregator_chain:
|
||||
* @pad: the pad to follow
|
||||
* @buf: the buffer to pass
|
||||
*
|
||||
* Chain a buffer on a pad.
|
||||
*/
|
||||
static void
|
||||
gst_aggregator_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstAggregator *aggregator;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
aggregator = GST_AGGREGATOR (gst_pad_get_parent (pad));
|
||||
/* gst_trace_add_entry (NULL, 0, buf, "aggregator buffer");*/
|
||||
|
||||
gst_aggregator_push (aggregator, pad, buf, (guchar *) "chain");
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstaggregator.h: Header for GstAggregator element
|
||||
*
|
||||
* 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_AGGREGATOR_H__
|
||||
#define __GST_AGGREGATOR_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef enum {
|
||||
AGGREGATOR_LOOP = 1,
|
||||
AGGREGATOR_LOOP_SELECT,
|
||||
AGGREGATOR_CHAIN
|
||||
} GstAggregatorSchedType;
|
||||
|
||||
#define GST_TYPE_AGGREGATOR \
|
||||
(gst_aggregator_get_type())
|
||||
#define GST_AGGREGATOR(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AGGREGATOR,GstAggregator))
|
||||
#define GST_AGGREGATOR_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AGGREGATOR,GstAggregatorClass))
|
||||
#define GST_IS_AGGREGATOR(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AGGREGATOR))
|
||||
#define GST_IS_AGGREGATOR_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGGREGATOR))
|
||||
|
||||
typedef struct _GstAggregator GstAggregator;
|
||||
typedef struct _GstAggregatorClass GstAggregatorClass;
|
||||
|
||||
struct _GstAggregator {
|
||||
GstElement element;
|
||||
|
||||
GstPad *srcpad;
|
||||
|
||||
gboolean silent;
|
||||
GstAggregatorSchedType sched;
|
||||
|
||||
gint numsinkpads;
|
||||
GList *sinkpads;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstAggregatorClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_aggregator_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_AGGREGATOR_H__ */
|
|
@ -1,468 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||
*
|
||||
* gstbufferstore.c: keep an easily accessible list of all buffers
|
||||
*
|
||||
* 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 "gstbufferstore.h"
|
||||
#include <gst/gstutils.h>
|
||||
#include <string.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_buffer_store_debug);
|
||||
#define GST_CAT_DEFAULT gst_buffer_store_debug
|
||||
|
||||
enum
|
||||
{
|
||||
CLEARED,
|
||||
BUFFER_ADDED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
enum
|
||||
{
|
||||
ARG_0
|
||||
};
|
||||
|
||||
|
||||
static void gst_buffer_store_dispose (GObject * object);
|
||||
|
||||
static gboolean gst_buffer_store_add_buffer_func (GstBufferStore * store,
|
||||
GstBuffer * buffer);
|
||||
static void gst_buffer_store_cleared_func (GstBufferStore * store);
|
||||
|
||||
static guint gst_buffer_store_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_buffer_store_debug, "GstBufferStore", 0, "buffer store helper");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstBufferStore, gst_buffer_store, GObject, G_TYPE_OBJECT,
|
||||
_do_init);
|
||||
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
debug_buffers (GstBufferStore * store)
|
||||
{
|
||||
GList *walk = store->buffers;
|
||||
|
||||
g_printerr ("BUFFERS in store:\n");
|
||||
while (walk) {
|
||||
g_print ("%15" G_GUINT64_FORMAT " - %7u\n", GST_BUFFER_OFFSET (walk->data),
|
||||
GST_BUFFER_SIZE (walk->data));
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
g_printerr ("\n");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
continue_accu (GSignalInvocationHint * ihint, GValue * return_accu,
|
||||
const GValue * handler_return, gpointer data)
|
||||
{
|
||||
gboolean do_continue = g_value_get_boolean (handler_return);
|
||||
|
||||
g_value_set_boolean (return_accu, do_continue);
|
||||
|
||||
return do_continue;
|
||||
}
|
||||
static void
|
||||
gst_buffer_store_base_init (gpointer g_class)
|
||||
{
|
||||
}
|
||||
static void
|
||||
gst_buffer_store_class_init (GstBufferStoreClass * store_class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (store_class);
|
||||
|
||||
gobject_class->dispose = gst_buffer_store_dispose;
|
||||
|
||||
gst_buffer_store_signals[CLEARED] = g_signal_new ("cleared",
|
||||
G_TYPE_FROM_CLASS (store_class), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstBufferStoreClass, cleared), NULL, NULL,
|
||||
gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||
gst_buffer_store_signals[BUFFER_ADDED] = g_signal_new ("buffer-added",
|
||||
G_TYPE_FROM_CLASS (store_class), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstBufferStoreClass, buffer_added), continue_accu, NULL,
|
||||
gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_BUFFER);
|
||||
|
||||
store_class->cleared = gst_buffer_store_cleared_func;
|
||||
store_class->buffer_added = gst_buffer_store_add_buffer_func;
|
||||
}
|
||||
static void
|
||||
gst_buffer_store_init (GstBufferStore * store)
|
||||
{
|
||||
store->buffers = NULL;
|
||||
}
|
||||
static void
|
||||
gst_buffer_store_dispose (GObject * object)
|
||||
{
|
||||
GstBufferStore *store = GST_BUFFER_STORE (object);
|
||||
|
||||
gst_buffer_store_clear (store);
|
||||
|
||||
parent_class->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_buffer_store_add_buffer_func (GstBufferStore * store, GstBuffer * buffer)
|
||||
{
|
||||
g_assert (buffer != NULL);
|
||||
|
||||
if (!GST_BUFFER_OFFSET_IS_VALID (buffer) &&
|
||||
store->buffers && GST_BUFFER_OFFSET_IS_VALID (store->buffers->data)) {
|
||||
/* we assumed valid offsets, but suddenly they are not anymore */
|
||||
GST_DEBUG_OBJECT (store,
|
||||
"attempting to add buffer %p with invalid offset to store with valid offset, abort",
|
||||
buffer);
|
||||
return FALSE;
|
||||
} else if (!store->buffers
|
||||
|| !GST_BUFFER_OFFSET_IS_VALID (store->buffers->data)) {
|
||||
/* the starting buffer had an invalid offset, in that case we assume continuous buffers */
|
||||
GST_LOG_OBJECT (store, "adding buffer %p with invalid offset and size %u",
|
||||
buffer, GST_BUFFER_SIZE (buffer));
|
||||
gst_data_ref (GST_DATA (buffer));
|
||||
store->buffers = g_list_append (store->buffers, buffer);
|
||||
return TRUE;
|
||||
} else {
|
||||
/* both list and buffer have valid offsets, we can really go wild */
|
||||
GList *walk, *current_list = NULL;
|
||||
GstBuffer *current;
|
||||
|
||||
g_assert (GST_BUFFER_OFFSET_IS_VALID (buffer));
|
||||
GST_LOG_OBJECT (store,
|
||||
"attempting to add buffer %p with offset %" G_GUINT64_FORMAT
|
||||
" and size %u", buffer, GST_BUFFER_OFFSET (buffer),
|
||||
GST_BUFFER_SIZE (buffer));
|
||||
/* we keep a sorted list of non-overlapping buffers */
|
||||
walk = store->buffers;
|
||||
while (walk) {
|
||||
current = GST_BUFFER (walk->data);
|
||||
current_list = walk;
|
||||
walk = g_list_next (walk);
|
||||
if (GST_BUFFER_OFFSET (current) < GST_BUFFER_OFFSET (buffer)) {
|
||||
continue;
|
||||
} else if (GST_BUFFER_OFFSET (current) == GST_BUFFER_OFFSET (buffer)) {
|
||||
guint needed_size;
|
||||
|
||||
if (walk) {
|
||||
needed_size = MIN (GST_BUFFER_SIZE (buffer),
|
||||
GST_BUFFER_OFFSET (walk->data) - GST_BUFFER_OFFSET (current));
|
||||
} else {
|
||||
needed_size = GST_BUFFER_SIZE (buffer);
|
||||
}
|
||||
if (needed_size <= GST_BUFFER_SIZE (current)) {
|
||||
buffer = NULL;
|
||||
break;
|
||||
} else {
|
||||
if (needed_size < GST_BUFFER_SIZE (buffer)) {
|
||||
/* need to create subbuffer to not have overlapping data */
|
||||
GstBuffer *sub = gst_buffer_create_sub (buffer, 0, needed_size);
|
||||
|
||||
g_assert (sub);
|
||||
buffer = sub;
|
||||
} else {
|
||||
gst_data_ref (GST_DATA (buffer));
|
||||
}
|
||||
/* replace current buffer with new one */
|
||||
GST_INFO_OBJECT (store,
|
||||
"replacing buffer %p with buffer %p with offset %" G_GINT64_FORMAT
|
||||
" and size %u", current_list->data, buffer,
|
||||
GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||
gst_data_unref (GST_DATA (current_list->data));
|
||||
current_list->data = buffer;
|
||||
buffer = NULL;
|
||||
break;
|
||||
}
|
||||
} else if (GST_BUFFER_OFFSET (current) > GST_BUFFER_OFFSET (buffer)) {
|
||||
GList *previous = g_list_previous (current_list);
|
||||
guint64 start_offset = previous ?
|
||||
GST_BUFFER_OFFSET (previous->data) +
|
||||
GST_BUFFER_SIZE (previous->data) : 0;
|
||||
|
||||
if (start_offset == GST_BUFFER_OFFSET (current)) {
|
||||
buffer = NULL;
|
||||
break;
|
||||
} else {
|
||||
/* we have data to insert */
|
||||
if (start_offset > GST_BUFFER_OFFSET (buffer) ||
|
||||
GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer) >
|
||||
GST_BUFFER_OFFSET (current)) {
|
||||
GstBuffer *sub;
|
||||
|
||||
/* need a subbuffer */
|
||||
start_offset = GST_BUFFER_OFFSET (buffer) > start_offset ? 0 :
|
||||
start_offset - GST_BUFFER_OFFSET (buffer);
|
||||
sub = gst_buffer_create_sub (buffer, start_offset,
|
||||
MIN (GST_BUFFER_SIZE (buffer) - start_offset,
|
||||
GST_BUFFER_OFFSET (current) - start_offset -
|
||||
GST_BUFFER_OFFSET (buffer)));
|
||||
g_assert (sub);
|
||||
GST_BUFFER_OFFSET (sub) = start_offset + GST_BUFFER_OFFSET (buffer);
|
||||
buffer = sub;
|
||||
} else {
|
||||
gst_data_ref (GST_DATA (buffer));
|
||||
}
|
||||
GST_INFO_OBJECT (store,
|
||||
"adding buffer %p with offset %" G_GINT64_FORMAT " and size %u",
|
||||
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||
store->buffers =
|
||||
g_list_insert_before (store->buffers, current_list, buffer);
|
||||
buffer = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buffer) {
|
||||
gst_data_ref (GST_DATA (buffer));
|
||||
GST_INFO_OBJECT (store,
|
||||
"adding buffer %p with offset %" G_GINT64_FORMAT " and size %u",
|
||||
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||
if (current_list) {
|
||||
g_list_append (current_list, buffer);
|
||||
} else {
|
||||
g_assert (store->buffers == NULL);
|
||||
store->buffers = g_list_prepend (NULL, buffer);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
static void
|
||||
gst_buffer_store_cleared_func (GstBufferStore * store)
|
||||
{
|
||||
g_list_foreach (store->buffers, (GFunc) gst_data_unref, NULL);
|
||||
g_list_free (store->buffers);
|
||||
store->buffers = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_buffer_store_new:
|
||||
*
|
||||
* Creates a new bufferstore.
|
||||
*
|
||||
* Returns: the new bufferstore.
|
||||
*/
|
||||
GstBufferStore *
|
||||
gst_buffer_store_new (void)
|
||||
{
|
||||
return GST_BUFFER_STORE (g_object_new (GST_TYPE_BUFFER_STORE, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_buffer_store_clear:
|
||||
* @store: a bufferstore
|
||||
*
|
||||
* Clears the buffer store. All buffers are removed and the buffer store
|
||||
* behaves like it was just created.
|
||||
*/
|
||||
/* FIXME: call this function _reset ? */
|
||||
void
|
||||
gst_buffer_store_clear (GstBufferStore * store)
|
||||
{
|
||||
g_return_if_fail (GST_IS_BUFFER_STORE (store));
|
||||
|
||||
g_signal_emit (store, gst_buffer_store_signals[CLEARED], 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_buffer_store_add_buffer:
|
||||
* @store: a bufferstore
|
||||
* @buffer: the buffer to add
|
||||
*
|
||||
* Adds a buffer to the buffer store.
|
||||
*
|
||||
* Returns: TRUE, if the buffer was added, FALSE if an error occured.
|
||||
*/
|
||||
gboolean
|
||||
gst_buffer_store_add_buffer (GstBufferStore * store, GstBuffer * buffer)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), FALSE);
|
||||
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
|
||||
|
||||
if (store->buffers &&
|
||||
GST_BUFFER_OFFSET_IS_VALID (store->buffers->data) &&
|
||||
!GST_BUFFER_OFFSET_IS_VALID (buffer))
|
||||
return FALSE;
|
||||
|
||||
g_signal_emit (store, gst_buffer_store_signals[BUFFER_ADDED], 0, buffer,
|
||||
&ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_buffer_store_get_buffer:
|
||||
* @store: a bufferstore
|
||||
* @offset: starting offset of returned buffer
|
||||
* @size: size of returned buffer
|
||||
*
|
||||
* Returns a buffer that corresponds to the given area of data. If part of the
|
||||
* data is not available inside the store, NULL is returned. You have to unref
|
||||
* the buffer after use.
|
||||
*
|
||||
* Returns: a buffer with the requested data or NULL if the data was not
|
||||
* available.
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_buffer_store_get_buffer (GstBufferStore * store, guint64 offset, guint size)
|
||||
{
|
||||
GstBuffer *current;
|
||||
GList *walk;
|
||||
guint8 *data;
|
||||
guint tmp;
|
||||
gboolean have_offset;
|
||||
guint64 cur_offset = 0;
|
||||
GstBuffer *ret = NULL;
|
||||
|
||||
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), NULL);
|
||||
|
||||
walk = store->buffers;
|
||||
if (!walk)
|
||||
return NULL;
|
||||
if (GST_BUFFER_OFFSET_IS_VALID (walk->data)) {
|
||||
have_offset = TRUE;
|
||||
} else {
|
||||
have_offset = FALSE;
|
||||
}
|
||||
while (walk) {
|
||||
current = GST_BUFFER (walk->data);
|
||||
if (have_offset) {
|
||||
cur_offset = GST_BUFFER_OFFSET (current);
|
||||
}
|
||||
walk = g_list_next (walk);
|
||||
if (cur_offset > offset) {
|
||||
/* #include <windows.h>
|
||||
do_nothing_loop (); */
|
||||
} else if (cur_offset == offset && GST_BUFFER_SIZE (current) == size) {
|
||||
GST_LOG_OBJECT (store,
|
||||
"found matching buffer %p for offset %" G_GUINT64_FORMAT
|
||||
" and size %u", current, offset, size);
|
||||
ret = current;
|
||||
gst_data_ref (GST_DATA (ret));
|
||||
GST_LOG_OBJECT (store, "refcount %d", GST_DATA_REFCOUNT_VALUE (ret));
|
||||
break;
|
||||
} else if (cur_offset + GST_BUFFER_SIZE (current) > offset) {
|
||||
if (cur_offset + GST_BUFFER_SIZE (current) >= offset + size) {
|
||||
ret = gst_buffer_create_sub (current, offset - cur_offset, size);
|
||||
GST_LOG_OBJECT (store,
|
||||
"created subbuffer %p from buffer %p for offset %llu and size %u",
|
||||
ret, current, offset, size);
|
||||
break;
|
||||
}
|
||||
/* uh, the requested data spans some buffers */
|
||||
ret = gst_buffer_new_and_alloc (size);
|
||||
GST_BUFFER_OFFSET (ret) = offset;
|
||||
GST_LOG_OBJECT (store, "created buffer %p for offset %" G_GUINT64_FORMAT
|
||||
" and size %u, will fill with data now", ret, offset, size);
|
||||
data = GST_BUFFER_DATA (ret);
|
||||
tmp = GST_BUFFER_SIZE (current) - offset + cur_offset;
|
||||
memcpy (data, GST_BUFFER_DATA (current) + offset - cur_offset, tmp);
|
||||
data += tmp;
|
||||
size -= tmp;
|
||||
while (size) {
|
||||
if (walk == NULL ||
|
||||
(have_offset &&
|
||||
GST_BUFFER_OFFSET (current) + GST_BUFFER_SIZE (current) !=
|
||||
GST_BUFFER_OFFSET (walk->data))) {
|
||||
GST_DEBUG_OBJECT (store,
|
||||
"not all data for offset %" G_GUINT64_FORMAT
|
||||
" and remaining size %u available, aborting", offset, size);
|
||||
gst_data_unref (GST_DATA (ret));
|
||||
ret = NULL;
|
||||
goto out;
|
||||
}
|
||||
current = GST_BUFFER (walk->data);
|
||||
walk = g_list_next (walk);
|
||||
tmp = MIN (GST_BUFFER_SIZE (current), size);
|
||||
memcpy (data, GST_BUFFER_DATA (current), tmp);
|
||||
data += tmp;
|
||||
size -= tmp;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
if (!have_offset) {
|
||||
cur_offset += GST_BUFFER_SIZE (current);
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_buffer_store_get_size:
|
||||
* @store: a bufferstore
|
||||
* @offset: desired offset
|
||||
*
|
||||
* Calculates the number of bytes available starting from offset. This allows
|
||||
* to query a buffer with the returned size.
|
||||
*
|
||||
* Returns: the number of continuous bytes in the bufferstore starting at
|
||||
* offset.
|
||||
*/
|
||||
guint
|
||||
gst_buffer_store_get_size (GstBufferStore * store, guint64 offset)
|
||||
{
|
||||
GList *walk;
|
||||
gboolean have_offset;
|
||||
gboolean counting = FALSE;
|
||||
guint64 cur_offset = 0;
|
||||
GstBuffer *current = NULL;
|
||||
guint ret = 0;
|
||||
|
||||
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), 0);
|
||||
|
||||
walk = store->buffers;
|
||||
if (!walk)
|
||||
return 0;
|
||||
if (GST_BUFFER_OFFSET_IS_VALID (walk->data)) {
|
||||
have_offset = TRUE;
|
||||
} else {
|
||||
have_offset = FALSE;
|
||||
}
|
||||
while (walk) {
|
||||
if (have_offset && counting &&
|
||||
cur_offset + GST_BUFFER_SIZE (current) !=
|
||||
GST_BUFFER_OFFSET (walk->data)) {
|
||||
break;
|
||||
}
|
||||
current = GST_BUFFER (walk->data);
|
||||
if (have_offset) {
|
||||
cur_offset = GST_BUFFER_OFFSET (current);
|
||||
}
|
||||
walk = g_list_next (walk);
|
||||
if (counting) {
|
||||
ret += GST_BUFFER_SIZE (current);
|
||||
} else {
|
||||
if (cur_offset > offset)
|
||||
return 0;
|
||||
if (cur_offset + GST_BUFFER_SIZE (current) > offset) {
|
||||
/* we have at least some bytes */
|
||||
ret = cur_offset + GST_BUFFER_SIZE (current) - offset;
|
||||
counting = TRUE;
|
||||
}
|
||||
}
|
||||
if (!have_offset) {
|
||||
cur_offset += GST_BUFFER_SIZE (current);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||
*
|
||||
* gsttypefind.h: keep an easily accessible list of all buffers
|
||||
*
|
||||
* 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_BUFFER_STORE_H__
|
||||
#define __GST_BUFFER_STORE_H__
|
||||
|
||||
#include <gst/gstbuffer.h>
|
||||
#include <gst/gstinfo.h>
|
||||
#include <gst/gstmarshal.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_BUFFER_STORE (gst_buffer_store_get_type ())
|
||||
#define GST_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_BUFFER_STORE, GstBufferStore))
|
||||
#define GST_IS_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_BUFFER_STORE))
|
||||
#define GST_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
|
||||
#define GST_IS_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_BUFFER_STORE))
|
||||
#define GST_BUFFER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
|
||||
|
||||
typedef struct _GstBufferStore GstBufferStore;
|
||||
typedef struct _GstBufferStoreClass GstBufferStoreClass;
|
||||
|
||||
struct _GstBufferStore {
|
||||
GObject object;
|
||||
|
||||
GList * buffers;
|
||||
};
|
||||
|
||||
struct _GstBufferStoreClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (* cleared) (GstBufferStore * store);
|
||||
gboolean (* buffer_added) (GstBufferStore * store,
|
||||
GstBuffer * buffer);
|
||||
};
|
||||
|
||||
GType gst_buffer_store_get_type (void);
|
||||
|
||||
GstBufferStore * gst_buffer_store_new (void);
|
||||
void gst_buffer_store_clear (GstBufferStore * store);
|
||||
|
||||
gboolean gst_buffer_store_add_buffer (GstBufferStore * store,
|
||||
GstBuffer * buffer);
|
||||
|
||||
GstBuffer * gst_buffer_store_get_buffer (GstBufferStore * store,
|
||||
guint64 offset,
|
||||
guint size);
|
||||
guint gst_buffer_store_get_size (GstBufferStore * store,
|
||||
guint64 offset);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_BUFFER_STORE_H__ */
|
|
@ -1,97 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstelements.c:
|
||||
*
|
||||
* 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 "gstaggregator.h"
|
||||
#include "gstfakesink.h"
|
||||
#include "gstfakesrc.h"
|
||||
#include "gstfdsink.h"
|
||||
#include "gstfdsrc.h"
|
||||
#include "gstfilesink.h"
|
||||
#include "gstfilesrc.h"
|
||||
#include "gstidentity.h"
|
||||
#include "gstmd5sink.h"
|
||||
#include "gstmultifilesrc.h"
|
||||
#include "gstpipefilter.h"
|
||||
#include "gstshaper.h"
|
||||
#include "gststatistics.h"
|
||||
#include "gsttee.h"
|
||||
#include "gsttypefindelement.h"
|
||||
|
||||
struct _elements_entry
|
||||
{
|
||||
gchar *name;
|
||||
guint rank;
|
||||
GType (*type) (void);
|
||||
};
|
||||
|
||||
|
||||
extern GType gst_filesrc_get_type (void);
|
||||
extern GstElementDetails gst_filesrc_details;
|
||||
|
||||
static struct _elements_entry _elements[] = {
|
||||
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
|
||||
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
||||
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
||||
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
||||
{"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
|
||||
{"filesrc", GST_RANK_PRIMARY, gst_filesrc_get_type},
|
||||
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
||||
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
||||
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
|
||||
#ifndef HAVE_WIN32
|
||||
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
|
||||
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
|
||||
#endif
|
||||
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
|
||||
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
|
||||
{"tee", GST_RANK_NONE, gst_tee_get_type},
|
||||
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
struct _elements_entry *my_elements = _elements;
|
||||
|
||||
while ((*my_elements).name) {
|
||||
if (!gst_element_register (plugin, (*my_elements).name, (*my_elements).rank,
|
||||
((*my_elements).type) ()))
|
||||
return FALSE;
|
||||
my_elements++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"gstelements",
|
||||
"standard GStreamer elements",
|
||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
|
|
@ -1,423 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfakesink.c:
|
||||
*
|
||||
* 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 "gstfakesink.h"
|
||||
#include <gst/gstmarshal.h>
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_fakesink_debug);
|
||||
#define GST_CAT_DEFAULT gst_fakesink_debug
|
||||
|
||||
GstElementDetails gst_fakesink_details = GST_ELEMENT_DETAILS ("Fake Sink",
|
||||
"Sink",
|
||||
"Black hole for data",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>");
|
||||
|
||||
|
||||
/* FakeSink signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
SIGNAL_HANDOFF,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_STATE_ERROR,
|
||||
ARG_NUM_SINKS,
|
||||
ARG_SILENT,
|
||||
ARG_DUMP,
|
||||
ARG_SYNC,
|
||||
ARG_SIGNAL_HANDOFFS,
|
||||
ARG_LAST_MESSAGE
|
||||
};
|
||||
|
||||
GstStaticPadTemplate fakesink_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define GST_TYPE_FAKESINK_STATE_ERROR (gst_fakesink_state_error_get_type())
|
||||
static GType
|
||||
gst_fakesink_state_error_get_type (void)
|
||||
{
|
||||
static GType fakesink_state_error_type = 0;
|
||||
static GEnumValue fakesink_state_error[] = {
|
||||
{FAKESINK_STATE_ERROR_NONE, "0", "No state change errors"},
|
||||
{FAKESINK_STATE_ERROR_NULL_READY, "1",
|
||||
"Fail state change from NULL to READY"},
|
||||
{FAKESINK_STATE_ERROR_READY_PAUSED, "2",
|
||||
"Fail state change from READY to PAUSED"},
|
||||
{FAKESINK_STATE_ERROR_PAUSED_PLAYING, "3",
|
||||
"Fail state change from PAUSED to PLAYING"},
|
||||
{FAKESINK_STATE_ERROR_PLAYING_PAUSED, "4",
|
||||
"Fail state change from PLAYING to PAUSED"},
|
||||
{FAKESINK_STATE_ERROR_PAUSED_READY, "5",
|
||||
"Fail state change from PAUSED to READY"},
|
||||
{FAKESINK_STATE_ERROR_READY_NULL, "6",
|
||||
"Fail state change from READY to NULL"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!fakesink_state_error_type) {
|
||||
fakesink_state_error_type =
|
||||
g_enum_register_static ("GstFakeSinkStateError", fakesink_state_error);
|
||||
}
|
||||
return fakesink_state_error_type;
|
||||
}
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFakeSink, gst_fakesink, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static void gst_fakesink_set_clock (GstElement * element, GstClock * clock);
|
||||
static GstPad *gst_fakesink_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * unused);
|
||||
|
||||
static void gst_fakesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fakesink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
|
||||
|
||||
static void gst_fakesink_chain (GstPad * pad, GstData * _data);
|
||||
|
||||
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gst_fakesink_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 (&sinktemplate));
|
||||
gst_element_class_set_details (gstelement_class, &gst_fakesink_details);
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&fakesink_sink_template));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_class_init (GstFakeSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
|
||||
g_param_spec_int ("num_sinks", "Number of sinks",
|
||||
"The number of sinkpads", 1, G_MAXINT, 1, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATE_ERROR,
|
||||
g_param_spec_enum ("state_error", "State Error",
|
||||
"Generate a state change error", GST_TYPE_FAKESINK_STATE_ERROR,
|
||||
FAKESINK_STATE_ERROR_NONE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "Last Message",
|
||||
"The message describing current status", NULL, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
|
||||
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_HANDOFFS,
|
||||
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
|
||||
"Send a signal before unreffing the buffer", FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "Silent",
|
||||
"Don't produce last_message events", FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump received bytes to stdout",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
|
||||
gst_fakesink_signals[SIGNAL_HANDOFF] =
|
||||
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstFakeSinkClass, handoff), NULL, NULL,
|
||||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
|
||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_fakesink_change_state);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_init (GstFakeSink * fakesink)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
|
||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
||||
|
||||
fakesink->silent = FALSE;
|
||||
fakesink->dump = FALSE;
|
||||
fakesink->sync = FALSE;
|
||||
fakesink->last_message = NULL;
|
||||
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
|
||||
fakesink->signal_handoffs = FALSE;
|
||||
|
||||
GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
sink = GST_FAKESINK (element);
|
||||
|
||||
sink->clock = clock;
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_fakesink_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
gchar *name;
|
||||
GstPad *sinkpad;
|
||||
GstFakeSink *fakesink;
|
||||
|
||||
g_return_val_if_fail (GST_IS_FAKESINK (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SINK) {
|
||||
g_warning ("gstfakesink: request new pad that is not a SINK pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fakesink = GST_FAKESINK (element);
|
||||
|
||||
name = g_strdup_printf ("sink%d", GST_ELEMENT (fakesink)->numsinkpads);
|
||||
|
||||
sinkpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (fakesink), sinkpad);
|
||||
|
||||
return sinkpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
sink = GST_FAKESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_SILENT:
|
||||
sink->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_STATE_ERROR:
|
||||
sink->state_error = g_value_get_enum (value);
|
||||
break;
|
||||
case ARG_DUMP:
|
||||
sink->dump = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_SYNC:
|
||||
sink->sync = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_SIGNAL_HANDOFFS:
|
||||
sink->signal_handoffs = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FAKESINK (object));
|
||||
|
||||
sink = GST_FAKESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_SINKS:
|
||||
g_value_set_int (value, GST_ELEMENT (sink)->numsinkpads);
|
||||
break;
|
||||
case ARG_STATE_ERROR:
|
||||
g_value_set_enum (value, sink->state_error);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, sink->silent);
|
||||
break;
|
||||
case ARG_DUMP:
|
||||
g_value_set_boolean (value, sink->dump);
|
||||
break;
|
||||
case ARG_SYNC:
|
||||
g_value_set_boolean (value, sink->sync);
|
||||
break;
|
||||
case ARG_SIGNAL_HANDOFFS:
|
||||
g_value_set_boolean (value, sink->signal_handoffs);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
g_value_set_string (value, sink->last_message);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesink_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstFakeSink *fakesink;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GstEvent *event = GST_EVENT (buf);
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
}
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
if (fakesink->sync && fakesink->clock) {
|
||||
gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||
|
||||
gst_element_set_time (GST_ELEMENT (fakesink), value);
|
||||
}
|
||||
default:
|
||||
gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fakesink->sync && fakesink->clock) {
|
||||
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
|
||||
}
|
||||
|
||||
if (!fakesink->silent) {
|
||||
g_free (fakesink->last_message);
|
||||
|
||||
fakesink->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)< (%d bytes, timestamp: %"
|
||||
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
|
||||
G_GINT64_FORMAT ", offset_end: %" G_GINT64_FORMAT ", flags: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (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_FLAGS (buf), buf);
|
||||
|
||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||
}
|
||||
|
||||
if (fakesink->signal_handoffs)
|
||||
g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
|
||||
buf, pad);
|
||||
|
||||
if (fakesink->dump) {
|
||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_fakesink_change_state (GstElement * element)
|
||||
{
|
||||
GstFakeSink *fakesink = GST_FAKESINK (element);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_NULL_READY)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
if (!GST_FLAG_IS_SET (fakesink, GST_ELEMENT_IN_ERROR) &&
|
||||
fakesink->state_error == FAKESINK_STATE_ERROR_PLAYING_PAUSED)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_READY)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_NULL)
|
||||
goto error;
|
||||
g_free (fakesink->last_message);
|
||||
fakesink->last_message = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
|
||||
error:
|
||||
GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
|
||||
return GST_STATE_FAILURE;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfakesink.h:
|
||||
*
|
||||
* 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_FAKESINK_H__
|
||||
#define __GST_FAKESINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_FAKESINK \
|
||||
(gst_fakesink_get_type())
|
||||
#define GST_FAKESINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FAKESINK,GstFakeSink))
|
||||
#define GST_FAKESINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FAKESINK,GstFakeSinkClass))
|
||||
#define GST_IS_FAKESINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FAKESINK))
|
||||
#define GST_IS_FAKESINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FAKESINK))
|
||||
|
||||
typedef enum {
|
||||
FAKESINK_STATE_ERROR_NONE = 0,
|
||||
FAKESINK_STATE_ERROR_NULL_READY,
|
||||
FAKESINK_STATE_ERROR_READY_PAUSED,
|
||||
FAKESINK_STATE_ERROR_PAUSED_PLAYING,
|
||||
FAKESINK_STATE_ERROR_PLAYING_PAUSED,
|
||||
FAKESINK_STATE_ERROR_PAUSED_READY,
|
||||
FAKESINK_STATE_ERROR_READY_NULL
|
||||
} GstFakeSinkStateError;
|
||||
|
||||
typedef struct _GstFakeSink GstFakeSink;
|
||||
typedef struct _GstFakeSinkClass GstFakeSinkClass;
|
||||
|
||||
struct _GstFakeSink {
|
||||
GstElement element;
|
||||
|
||||
gboolean silent;
|
||||
gboolean dump;
|
||||
gboolean sync;
|
||||
gboolean signal_handoffs;
|
||||
GstClock *clock;
|
||||
GstFakeSinkStateError state_error;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstFakeSinkClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
|
||||
};
|
||||
|
||||
GType gst_fakesink_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FAKESINK_H__ */
|
|
@ -1,948 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfakesrc.c:
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstfakesrc.h"
|
||||
#include <gst/gstmarshal.h>
|
||||
|
||||
#define DEFAULT_SIZEMIN 0
|
||||
#define DEFAULT_SIZEMAX 4096
|
||||
#define DEFAULT_PARENTSIZE 4096*10
|
||||
#define DEFAULT_DATARATE 0
|
||||
#define DEFAULT_SYNC FALSE
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_fakesrc_debug);
|
||||
#define GST_CAT_DEFAULT gst_fakesrc_debug
|
||||
|
||||
GstElementDetails gst_fakesrc_details = GST_ELEMENT_DETAILS ("Fake Source",
|
||||
"Source",
|
||||
"Push empty (no data) buffers around",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim.taymans@chello.be>");
|
||||
|
||||
|
||||
/* FakeSrc signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
SIGNAL_HANDOFF,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_NUM_SOURCES,
|
||||
ARG_LOOP_BASED,
|
||||
ARG_OUTPUT,
|
||||
ARG_DATA,
|
||||
ARG_SIZETYPE,
|
||||
ARG_SIZEMIN,
|
||||
ARG_SIZEMAX,
|
||||
ARG_FILLTYPE,
|
||||
ARG_DATARATE,
|
||||
ARG_SYNC,
|
||||
ARG_PATTERN,
|
||||
ARG_NUM_BUFFERS,
|
||||
ARG_EOS,
|
||||
ARG_SIGNAL_HANDOFFS,
|
||||
ARG_SILENT,
|
||||
ARG_DUMP,
|
||||
ARG_PARENTSIZE,
|
||||
ARG_LAST_MESSAGE
|
||||
};
|
||||
|
||||
GstStaticPadTemplate fakesrc_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define GST_TYPE_FAKESRC_OUTPUT (gst_fakesrc_output_get_type())
|
||||
static GType
|
||||
gst_fakesrc_output_get_type (void)
|
||||
{
|
||||
static GType fakesrc_output_type = 0;
|
||||
static GEnumValue fakesrc_output[] = {
|
||||
{FAKESRC_FIRST_LAST_LOOP, "1", "First-Last loop"},
|
||||
{FAKESRC_LAST_FIRST_LOOP, "2", "Last-First loop"},
|
||||
{FAKESRC_PING_PONG, "3", "Ping-Pong"},
|
||||
{FAKESRC_ORDERED_RANDOM, "4", "Ordered Random"},
|
||||
{FAKESRC_RANDOM, "5", "Random"},
|
||||
{FAKESRC_PATTERN_LOOP, "6", "Patttern loop"},
|
||||
{FAKESRC_PING_PONG_PATTERN, "7", "Ping-Pong Pattern"},
|
||||
{FAKESRC_GET_ALWAYS_SUCEEDS, "8", "'_get' Always succeeds"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!fakesrc_output_type) {
|
||||
fakesrc_output_type =
|
||||
g_enum_register_static ("GstFakeSrcOutput", fakesrc_output);
|
||||
}
|
||||
return fakesrc_output_type;
|
||||
}
|
||||
|
||||
#define GST_TYPE_FAKESRC_DATA (gst_fakesrc_data_get_type())
|
||||
static GType
|
||||
gst_fakesrc_data_get_type (void)
|
||||
{
|
||||
static GType fakesrc_data_type = 0;
|
||||
static GEnumValue fakesrc_data[] = {
|
||||
{FAKESRC_DATA_ALLOCATE, "1", "Allocate data"},
|
||||
{FAKESRC_DATA_SUBBUFFER, "2", "Subbuffer data"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!fakesrc_data_type) {
|
||||
fakesrc_data_type = g_enum_register_static ("GstFakeSrcData", fakesrc_data);
|
||||
}
|
||||
return fakesrc_data_type;
|
||||
}
|
||||
|
||||
#define GST_TYPE_FAKESRC_SIZETYPE (gst_fakesrc_sizetype_get_type())
|
||||
static GType
|
||||
gst_fakesrc_sizetype_get_type (void)
|
||||
{
|
||||
static GType fakesrc_sizetype_type = 0;
|
||||
static GEnumValue fakesrc_sizetype[] = {
|
||||
{FAKESRC_SIZETYPE_NULL, "1", "Send empty buffers"},
|
||||
{FAKESRC_SIZETYPE_FIXED, "2", "Fixed size buffers (sizemax sized)"},
|
||||
{FAKESRC_SIZETYPE_RANDOM, "3",
|
||||
"Random sized buffers (sizemin <= size <= sizemax)"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!fakesrc_sizetype_type) {
|
||||
fakesrc_sizetype_type =
|
||||
g_enum_register_static ("GstFakeSrcSizeType", fakesrc_sizetype);
|
||||
}
|
||||
return fakesrc_sizetype_type;
|
||||
}
|
||||
|
||||
#define GST_TYPE_FAKESRC_FILLTYPE (gst_fakesrc_filltype_get_type())
|
||||
static GType
|
||||
gst_fakesrc_filltype_get_type (void)
|
||||
{
|
||||
static GType fakesrc_filltype_type = 0;
|
||||
static GEnumValue fakesrc_filltype[] = {
|
||||
{FAKESRC_FILLTYPE_NOTHING, "1", "Leave data as malloced"},
|
||||
{FAKESRC_FILLTYPE_NULL, "2", "Fill buffers with zeros"},
|
||||
{FAKESRC_FILLTYPE_RANDOM, "3", "Fill buffers with random crap"},
|
||||
{FAKESRC_FILLTYPE_PATTERN, "4", "Fill buffers with pattern 0x00 -> 0xff"},
|
||||
{FAKESRC_FILLTYPE_PATTERN_CONT, "5",
|
||||
"Fill buffers with pattern 0x00 -> 0xff that spans buffers"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!fakesrc_filltype_type) {
|
||||
fakesrc_filltype_type =
|
||||
g_enum_register_static ("GstFakeSrcFillType", fakesrc_filltype);
|
||||
}
|
||||
return fakesrc_filltype_type;
|
||||
}
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * unused);
|
||||
static void gst_fakesrc_update_functions (GstFakeSrc * src);
|
||||
static void gst_fakesrc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fakesrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
|
||||
|
||||
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
|
||||
|
||||
static GstData *gst_fakesrc_get (GstPad * pad);
|
||||
static void gst_fakesrc_loop (GstElement * element);
|
||||
|
||||
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gst_fakesrc_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 (gstelement_class, &gst_fakesrc_details);
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&fakesrc_src_template));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_class_init (GstFakeSrcClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
|
||||
g_param_spec_int ("num-sources", "num-sources", "Number of sources",
|
||||
1, G_MAXINT, 1, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
|
||||
g_param_spec_boolean ("loop-based", "loop-based",
|
||||
"Enable loop-based operation", FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OUTPUT,
|
||||
g_param_spec_enum ("output", "output", "Output method (currently unused)",
|
||||
GST_TYPE_FAKESRC_OUTPUT, FAKESRC_FIRST_LAST_LOOP, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATA,
|
||||
g_param_spec_enum ("data", "data", "Data allocation method",
|
||||
GST_TYPE_FAKESRC_DATA, FAKESRC_DATA_ALLOCATE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZETYPE,
|
||||
g_param_spec_enum ("sizetype", "sizetype",
|
||||
"How to determine buffer sizes", GST_TYPE_FAKESRC_SIZETYPE,
|
||||
FAKESRC_SIZETYPE_NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMIN,
|
||||
g_param_spec_int ("sizemin", "sizemin", "Minimum buffer size", 0,
|
||||
G_MAXINT, DEFAULT_SIZEMIN, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMAX,
|
||||
g_param_spec_int ("sizemax", "sizemax", "Maximum buffer size", 0,
|
||||
G_MAXINT, DEFAULT_SIZEMAX, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PARENTSIZE,
|
||||
g_param_spec_int ("parentsize", "parentsize",
|
||||
"Size of parent buffer for sub-buffered allocation", 0, G_MAXINT,
|
||||
DEFAULT_PARENTSIZE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILLTYPE,
|
||||
g_param_spec_enum ("filltype", "filltype",
|
||||
"How to fill the buffer, if at all", GST_TYPE_FAKESRC_FILLTYPE,
|
||||
FAKESRC_FILLTYPE_NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATARATE,
|
||||
g_param_spec_int ("datarate", "Datarate",
|
||||
"Timestamps buffers with number of bytes per second (0 = none)", 0,
|
||||
G_MAXINT, DEFAULT_DATARATE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
|
||||
g_param_spec_boolean ("sync", "Sync", "Sync to the clock to the datarate",
|
||||
DEFAULT_SYNC, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PATTERN,
|
||||
g_param_spec_string ("pattern", "pattern", "pattern", NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_BUFFERS,
|
||||
g_param_spec_int ("num-buffers", "num-buffers",
|
||||
"Number of buffers to output before sending EOS", -1, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EOS,
|
||||
g_param_spec_boolean ("eos", "eos", "Send out the EOS event?", TRUE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last-message", "last-message",
|
||||
"The last status message", NULL, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "Silent",
|
||||
"Don't produce last_message events", FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_HANDOFFS,
|
||||
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
|
||||
"Send a signal before pushing the buffer", FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump produced bytes to stdout",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
|
||||
gst_fakesrc_signals[SIGNAL_HANDOFF] =
|
||||
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL,
|
||||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
|
||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
|
||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesrc_set_clock);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_init (GstFakeSrc * fakesrc)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
/* create our first output pad */
|
||||
pad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_element_add_pad (GST_ELEMENT (fakesrc), pad);
|
||||
|
||||
fakesrc->loop_based = FALSE;
|
||||
gst_fakesrc_update_functions (fakesrc);
|
||||
|
||||
fakesrc->output = FAKESRC_FIRST_LAST_LOOP;
|
||||
fakesrc->segment_start = -1;
|
||||
fakesrc->segment_end = -1;
|
||||
fakesrc->num_buffers = -1;
|
||||
fakesrc->rt_num_buffers = -1;
|
||||
fakesrc->buffer_count = 0;
|
||||
fakesrc->silent = FALSE;
|
||||
fakesrc->signal_handoffs = FALSE;
|
||||
fakesrc->dump = FALSE;
|
||||
fakesrc->pattern_byte = 0x00;
|
||||
fakesrc->need_flush = FALSE;
|
||||
fakesrc->data = FAKESRC_DATA_ALLOCATE;
|
||||
fakesrc->sizetype = FAKESRC_SIZETYPE_NULL;
|
||||
fakesrc->filltype = FAKESRC_FILLTYPE_NOTHING;
|
||||
fakesrc->sizemin = DEFAULT_SIZEMIN;
|
||||
fakesrc->sizemax = DEFAULT_SIZEMAX;
|
||||
fakesrc->parent = NULL;
|
||||
fakesrc->parentsize = DEFAULT_PARENTSIZE;
|
||||
fakesrc->last_message = NULL;
|
||||
fakesrc->datarate = DEFAULT_DATARATE;
|
||||
fakesrc->sync = DEFAULT_SYNC;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
|
||||
src = GST_FAKESRC (element);
|
||||
|
||||
src->clock = clock;
|
||||
}
|
||||
|
||||
|
||||
static GstPad *
|
||||
gst_fakesrc_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
gchar *name;
|
||||
GstPad *srcpad;
|
||||
GstFakeSrc *fakesrc;
|
||||
|
||||
g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SRC) {
|
||||
g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fakesrc = GST_FAKESRC (element);
|
||||
|
||||
name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
|
||||
|
||||
srcpad = gst_pad_new_from_template (templ, name);
|
||||
gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
|
||||
gst_fakesrc_update_functions (fakesrc);
|
||||
|
||||
g_free (name);
|
||||
|
||||
return srcpad;
|
||||
}
|
||||
|
||||
static const GstFormat *
|
||||
gst_fakesrc_get_formats (GstPad * pad)
|
||||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_DEFAULT,
|
||||
0,
|
||||
};
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
static const GstQueryType *
|
||||
gst_fakesrc_get_query_types (GstPad * pad)
|
||||
{
|
||||
static const GstQueryType types[] = {
|
||||
GST_QUERY_TOTAL,
|
||||
GST_QUERY_POSITION,
|
||||
GST_QUERY_START,
|
||||
GST_QUERY_SEGMENT_END,
|
||||
0,
|
||||
};
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fakesrc_query (GstPad * pad, GstQueryType type,
|
||||
GstFormat * format, gint64 * value)
|
||||
{
|
||||
GstFakeSrc *src = GST_FAKESRC (GST_PAD_PARENT (pad));
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_TOTAL:
|
||||
*value = src->num_buffers;
|
||||
break;
|
||||
case GST_QUERY_POSITION:
|
||||
*value = src->buffer_count;
|
||||
break;
|
||||
case GST_QUERY_START:
|
||||
*value = src->segment_start;
|
||||
break;
|
||||
case GST_QUERY_SEGMENT_END:
|
||||
*value = src->segment_end;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const GstEventMask *
|
||||
gst_fakesrc_get_event_mask (GstPad * pad)
|
||||
{
|
||||
static const GstEventMask masks[] = {
|
||||
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH},
|
||||
{GST_EVENT_SEEK_SEGMENT, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
|
||||
{GST_EVENT_FLUSH, 0},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
return masks;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
|
||||
src = GST_FAKESRC (gst_pad_get_parent (pad));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
|
||||
|
||||
if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
|
||||
break;
|
||||
}
|
||||
/* else we do a flush too */
|
||||
case GST_EVENT_SEEK_SEGMENT:
|
||||
src->segment_start = GST_EVENT_SEEK_OFFSET (event);
|
||||
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
|
||||
src->buffer_count = src->segment_start;
|
||||
src->segment_loop =
|
||||
GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
|
||||
break;
|
||||
case GST_EVENT_FLUSH:
|
||||
src->need_flush = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gst_event_unref (event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_update_functions (GstFakeSrc * src)
|
||||
{
|
||||
GList *pads;
|
||||
|
||||
if (src->loop_based) {
|
||||
gst_element_set_loop_function (GST_ELEMENT (src),
|
||||
GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
|
||||
} else {
|
||||
gst_element_set_loop_function (GST_ELEMENT (src), NULL);
|
||||
}
|
||||
|
||||
pads = GST_ELEMENT (src)->pads;
|
||||
while (pads) {
|
||||
GstPad *pad = GST_PAD (pads->data);
|
||||
|
||||
if (src->loop_based) {
|
||||
gst_pad_set_get_function (pad, NULL);
|
||||
} else {
|
||||
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
|
||||
}
|
||||
|
||||
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
|
||||
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
|
||||
gst_pad_set_query_function (pad, gst_fakesrc_query);
|
||||
gst_pad_set_query_type_function (pad, gst_fakesrc_get_query_types);
|
||||
gst_pad_set_formats_function (pad, gst_fakesrc_get_formats);
|
||||
pads = g_list_next (pads);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_alloc_parent (GstFakeSrc * src)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
buf = gst_buffer_new ();
|
||||
GST_BUFFER_DATA (buf) = g_malloc (src->parentsize);
|
||||
GST_BUFFER_SIZE (buf) = src->parentsize;
|
||||
|
||||
src->parent = buf;
|
||||
src->parentoffset = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
src = GST_FAKESRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOOP_BASED:
|
||||
src->loop_based = g_value_get_boolean (value);
|
||||
gst_fakesrc_update_functions (src);
|
||||
break;
|
||||
case ARG_OUTPUT:
|
||||
g_warning ("not yet implemented");
|
||||
break;
|
||||
case ARG_DATA:
|
||||
src->data = g_value_get_enum (value);
|
||||
|
||||
if (src->data == FAKESRC_DATA_SUBBUFFER) {
|
||||
if (!src->parent)
|
||||
gst_fakesrc_alloc_parent (src);
|
||||
} else {
|
||||
if (src->parent) {
|
||||
gst_buffer_unref (src->parent);
|
||||
src->parent = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ARG_SIZETYPE:
|
||||
src->sizetype = g_value_get_enum (value);
|
||||
break;
|
||||
case ARG_SIZEMIN:
|
||||
src->sizemin = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_SIZEMAX:
|
||||
src->sizemax = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_PARENTSIZE:
|
||||
src->parentsize = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_FILLTYPE:
|
||||
src->filltype = g_value_get_enum (value);
|
||||
break;
|
||||
case ARG_DATARATE:
|
||||
src->datarate = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_SYNC:
|
||||
src->sync = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_PATTERN:
|
||||
break;
|
||||
case ARG_NUM_BUFFERS:
|
||||
src->num_buffers = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_EOS:
|
||||
src->eos = g_value_get_boolean (value);
|
||||
GST_INFO ("will EOS on next buffer");
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
src->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_SIGNAL_HANDOFFS:
|
||||
src->signal_handoffs = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_DUMP:
|
||||
src->dump = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FAKESRC (object));
|
||||
|
||||
src = GST_FAKESRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_SOURCES:
|
||||
g_value_set_int (value, GST_ELEMENT (src)->numsrcpads);
|
||||
break;
|
||||
case ARG_LOOP_BASED:
|
||||
g_value_set_boolean (value, src->loop_based);
|
||||
break;
|
||||
case ARG_OUTPUT:
|
||||
g_value_set_enum (value, src->output);
|
||||
break;
|
||||
case ARG_DATA:
|
||||
g_value_set_enum (value, src->data);
|
||||
break;
|
||||
case ARG_SIZETYPE:
|
||||
g_value_set_enum (value, src->sizetype);
|
||||
break;
|
||||
case ARG_SIZEMIN:
|
||||
g_value_set_int (value, src->sizemin);
|
||||
break;
|
||||
case ARG_SIZEMAX:
|
||||
g_value_set_int (value, src->sizemax);
|
||||
break;
|
||||
case ARG_PARENTSIZE:
|
||||
g_value_set_int (value, src->parentsize);
|
||||
break;
|
||||
case ARG_FILLTYPE:
|
||||
g_value_set_enum (value, src->filltype);
|
||||
break;
|
||||
case ARG_DATARATE:
|
||||
g_value_set_int (value, src->datarate);
|
||||
break;
|
||||
case ARG_SYNC:
|
||||
g_value_set_boolean (value, src->sync);
|
||||
break;
|
||||
case ARG_PATTERN:
|
||||
g_value_set_string (value, src->pattern);
|
||||
break;
|
||||
case ARG_NUM_BUFFERS:
|
||||
g_value_set_int (value, src->num_buffers);
|
||||
break;
|
||||
case ARG_EOS:
|
||||
g_value_set_boolean (value, src->eos);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, src->silent);
|
||||
break;
|
||||
case ARG_SIGNAL_HANDOFFS:
|
||||
g_value_set_boolean (value, src->signal_handoffs);
|
||||
break;
|
||||
case ARG_DUMP:
|
||||
g_value_set_boolean (value, src->dump);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
g_value_set_string (value, src->last_message);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fakesrc_prepare_buffer (GstFakeSrc * src, GstBuffer * buf)
|
||||
{
|
||||
if (GST_BUFFER_SIZE (buf) == 0)
|
||||
return;
|
||||
|
||||
switch (src->filltype) {
|
||||
case FAKESRC_FILLTYPE_NULL:
|
||||
memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
|
||||
break;
|
||||
case FAKESRC_FILLTYPE_RANDOM:
|
||||
{
|
||||
gint i;
|
||||
guint8 *ptr = GST_BUFFER_DATA (buf);
|
||||
|
||||
for (i = GST_BUFFER_SIZE (buf); i; i--) {
|
||||
*ptr++ = (gint8) ((255.0) * rand () / (RAND_MAX));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FAKESRC_FILLTYPE_PATTERN:
|
||||
src->pattern_byte = 0x00;
|
||||
case FAKESRC_FILLTYPE_PATTERN_CONT:
|
||||
{
|
||||
gint i;
|
||||
guint8 *ptr = GST_BUFFER_DATA (buf);
|
||||
|
||||
for (i = GST_BUFFER_SIZE (buf); i; i--) {
|
||||
*ptr++ = src->pattern_byte++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FAKESRC_FILLTYPE_NOTHING:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_fakesrc_alloc_buffer (GstFakeSrc * src, guint size)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
buf = gst_buffer_new ();
|
||||
GST_BUFFER_SIZE (buf) = size;
|
||||
|
||||
if (size != 0) {
|
||||
switch (src->filltype) {
|
||||
case FAKESRC_FILLTYPE_NOTHING:
|
||||
GST_BUFFER_DATA (buf) = g_malloc (size);
|
||||
break;
|
||||
case FAKESRC_FILLTYPE_NULL:
|
||||
GST_BUFFER_DATA (buf) = g_malloc0 (size);
|
||||
break;
|
||||
case FAKESRC_FILLTYPE_RANDOM:
|
||||
case FAKESRC_FILLTYPE_PATTERN:
|
||||
case FAKESRC_FILLTYPE_PATTERN_CONT:
|
||||
default:
|
||||
GST_BUFFER_DATA (buf) = g_malloc (size);
|
||||
gst_fakesrc_prepare_buffer (src, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static guint
|
||||
gst_fakesrc_get_size (GstFakeSrc * src)
|
||||
{
|
||||
guint size;
|
||||
|
||||
switch (src->sizetype) {
|
||||
case FAKESRC_SIZETYPE_FIXED:
|
||||
size = src->sizemax;
|
||||
break;
|
||||
case FAKESRC_SIZETYPE_RANDOM:
|
||||
size =
|
||||
src->sizemin +
|
||||
(guint8) (((gfloat) src->sizemax) * rand () / (RAND_MAX +
|
||||
(gfloat) src->sizemin));
|
||||
break;
|
||||
case FAKESRC_SIZETYPE_NULL:
|
||||
default:
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_fakesrc_create_buffer (GstFakeSrc * src)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
guint size;
|
||||
gboolean dump = src->dump;
|
||||
|
||||
size = gst_fakesrc_get_size (src);
|
||||
if (size == 0)
|
||||
return gst_buffer_new ();
|
||||
|
||||
switch (src->data) {
|
||||
case FAKESRC_DATA_ALLOCATE:
|
||||
buf = gst_fakesrc_alloc_buffer (src, size);
|
||||
break;
|
||||
case FAKESRC_DATA_SUBBUFFER:
|
||||
/* see if we have a parent to subbuffer */
|
||||
if (!src->parent) {
|
||||
gst_fakesrc_alloc_parent (src);
|
||||
g_assert (src->parent);
|
||||
}
|
||||
/* see if it's large enough */
|
||||
if ((GST_BUFFER_SIZE (src->parent) - src->parentoffset) >= size) {
|
||||
buf = gst_buffer_create_sub (src->parent, src->parentoffset, size);
|
||||
src->parentoffset += size;
|
||||
} else {
|
||||
/* the parent is useless now */
|
||||
gst_buffer_unref (src->parent);
|
||||
src->parent = NULL;
|
||||
/* try again (this will allocate a new parent) */
|
||||
return gst_fakesrc_create_buffer (src);
|
||||
}
|
||||
gst_fakesrc_prepare_buffer (src, buf);
|
||||
break;
|
||||
default:
|
||||
g_warning ("fakesrc: dunno how to allocate buffers !");
|
||||
buf = gst_buffer_new ();
|
||||
break;
|
||||
}
|
||||
if (dump) {
|
||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static GstData *
|
||||
gst_fakesrc_get (GstPad * pad)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
GstBuffer *buf;
|
||||
GstClockTime time;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
|
||||
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
|
||||
|
||||
if (src->need_flush) {
|
||||
src->need_flush = FALSE;
|
||||
return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
|
||||
}
|
||||
|
||||
if (src->buffer_count == src->segment_end) {
|
||||
if (src->segment_loop) {
|
||||
return GST_DATA (gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||
} else {
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
}
|
||||
}
|
||||
|
||||
if (src->rt_num_buffers == 0) {
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
} else {
|
||||
if (src->rt_num_buffers > 0)
|
||||
src->rt_num_buffers--;
|
||||
}
|
||||
|
||||
if (src->eos) {
|
||||
GST_INFO ("fakesrc is setting eos on pad");
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
}
|
||||
|
||||
buf = gst_fakesrc_create_buffer (src);
|
||||
GST_BUFFER_OFFSET (buf) = src->buffer_count++;
|
||||
|
||||
time = GST_CLOCK_TIME_NONE;
|
||||
|
||||
if (src->datarate > 0) {
|
||||
time = (src->bytes_sent * GST_SECOND) / src->datarate;
|
||||
if (src->sync) {
|
||||
gst_element_wait (GST_ELEMENT (src), time);
|
||||
}
|
||||
|
||||
GST_BUFFER_DURATION (buf) =
|
||||
GST_BUFFER_SIZE (buf) * GST_SECOND / src->datarate;
|
||||
}
|
||||
GST_BUFFER_TIMESTAMP (buf) = time;
|
||||
|
||||
if (!src->silent) {
|
||||
g_free (src->last_message);
|
||||
|
||||
src->last_message =
|
||||
g_strdup_printf ("get ******* (%s:%s)> (%d bytes, %"
|
||||
G_GUINT64_FORMAT " ) %p", GST_DEBUG_PAD_NAME (pad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
|
||||
|
||||
g_object_notify (G_OBJECT (src), "last_message");
|
||||
}
|
||||
|
||||
if (src->signal_handoffs) {
|
||||
GST_LOG_OBJECT (src, "pre handoff emit");
|
||||
g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0,
|
||||
buf, pad);
|
||||
GST_LOG_OBJECT (src, "post handoff emit");
|
||||
}
|
||||
|
||||
src->bytes_sent += GST_BUFFER_SIZE (buf);
|
||||
|
||||
return GST_DATA (buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_fakesrc_loop:
|
||||
* @element: the faksesrc to loop
|
||||
*
|
||||
* generate an empty buffer and push it to the next element.
|
||||
*/
|
||||
static void
|
||||
gst_fakesrc_loop (GstElement * element)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
const GList *pads;
|
||||
|
||||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_FAKESRC (element));
|
||||
|
||||
src = GST_FAKESRC (element);
|
||||
|
||||
pads = gst_element_get_pad_list (element);
|
||||
|
||||
while (pads) {
|
||||
GstPad *pad = GST_PAD (pads->data);
|
||||
GstData *data;
|
||||
|
||||
data = gst_fakesrc_get (pad);
|
||||
gst_pad_push (pad, data);
|
||||
|
||||
if (src->eos) {
|
||||
return;
|
||||
}
|
||||
|
||||
pads = g_list_next (pads);
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_fakesrc_change_state (GstElement * element)
|
||||
{
|
||||
GstFakeSrc *fakesrc;
|
||||
|
||||
g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
|
||||
|
||||
fakesrc = GST_FAKESRC (element);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
fakesrc->buffer_count = 0;
|
||||
fakesrc->pattern_byte = 0x00;
|
||||
fakesrc->need_flush = FALSE;
|
||||
fakesrc->eos = FALSE;
|
||||
fakesrc->bytes_sent = 0;
|
||||
fakesrc->rt_num_buffers = fakesrc->num_buffers;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
if (fakesrc->parent) {
|
||||
gst_buffer_unref (fakesrc->parent);
|
||||
fakesrc->parent = NULL;
|
||||
}
|
||||
g_free (fakesrc->last_message);
|
||||
fakesrc->last_message = NULL;
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfakesrc.h:
|
||||
*
|
||||
* 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_FAKESRC_H__
|
||||
#define __GST_FAKESRC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef enum {
|
||||
FAKESRC_FIRST_LAST_LOOP = 1,
|
||||
FAKESRC_LAST_FIRST_LOOP,
|
||||
FAKESRC_PING_PONG,
|
||||
FAKESRC_ORDERED_RANDOM,
|
||||
FAKESRC_RANDOM,
|
||||
FAKESRC_PATTERN_LOOP,
|
||||
FAKESRC_PING_PONG_PATTERN,
|
||||
FAKESRC_GET_ALWAYS_SUCEEDS
|
||||
} GstFakeSrcOutputType;
|
||||
|
||||
typedef enum {
|
||||
FAKESRC_DATA_ALLOCATE = 1,
|
||||
FAKESRC_DATA_SUBBUFFER
|
||||
} GstFakeSrcDataType;
|
||||
|
||||
typedef enum {
|
||||
FAKESRC_SIZETYPE_NULL = 1,
|
||||
FAKESRC_SIZETYPE_FIXED,
|
||||
FAKESRC_SIZETYPE_RANDOM
|
||||
} GstFakeSrcSizeType;
|
||||
|
||||
typedef enum {
|
||||
FAKESRC_FILLTYPE_NOTHING = 1,
|
||||
FAKESRC_FILLTYPE_NULL,
|
||||
FAKESRC_FILLTYPE_RANDOM,
|
||||
FAKESRC_FILLTYPE_PATTERN,
|
||||
FAKESRC_FILLTYPE_PATTERN_CONT
|
||||
} GstFakeSrcFillType;
|
||||
|
||||
#define GST_TYPE_FAKESRC \
|
||||
(gst_fakesrc_get_type())
|
||||
#define GST_FAKESRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FAKESRC,GstFakeSrc))
|
||||
#define GST_FAKESRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FAKESRC,GstFakeSrcClass))
|
||||
#define GST_IS_FAKESRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FAKESRC))
|
||||
#define GST_IS_FAKESRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FAKESRC))
|
||||
|
||||
typedef struct _GstFakeSrc GstFakeSrc;
|
||||
typedef struct _GstFakeSrcClass GstFakeSrcClass;
|
||||
|
||||
struct _GstFakeSrc {
|
||||
GstElement element;
|
||||
|
||||
gboolean loop_based;
|
||||
gboolean eos;
|
||||
|
||||
GstFakeSrcOutputType output;
|
||||
GstFakeSrcDataType data;
|
||||
GstFakeSrcSizeType sizetype;
|
||||
GstFakeSrcFillType filltype;
|
||||
|
||||
guint sizemin;
|
||||
guint sizemax;
|
||||
GstBuffer *parent;
|
||||
guint parentsize;
|
||||
guint parentoffset;
|
||||
guint8 pattern_byte;
|
||||
gchar *pattern;
|
||||
GList *patternlist;
|
||||
gint datarate;
|
||||
gboolean sync;
|
||||
GstClock *clock;
|
||||
gint64 segment_start;
|
||||
gint64 segment_end;
|
||||
gboolean segment_loop;
|
||||
gint num_buffers;
|
||||
gint rt_num_buffers; /* we are going to change this at runtime */
|
||||
guint64 buffer_count;
|
||||
gboolean silent;
|
||||
gboolean signal_handoffs;
|
||||
gboolean dump;
|
||||
gboolean need_flush;
|
||||
|
||||
guint64 bytes_sent;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstFakeSrcClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
|
||||
};
|
||||
|
||||
GType gst_fakesrc_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FAKESRC_H__ */
|
|
@ -1,176 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfdsink.c:
|
||||
*
|
||||
* 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 "gstfdsink.h"
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_fdsink_debug);
|
||||
#define GST_CAT_DEFAULT gst_fdsink_debug
|
||||
|
||||
GstElementDetails gst_fdsink_details =
|
||||
GST_ELEMENT_DETAILS ("Filedescriptor Sink",
|
||||
"Sink/File",
|
||||
"Write data to a file descriptor",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>");
|
||||
|
||||
|
||||
/* FdSink signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_FD
|
||||
};
|
||||
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFdSink, gst_fdsink, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static void gst_fdsink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fdsink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_fdsink_chain (GstPad * pad, GstData * _data);
|
||||
|
||||
|
||||
static void
|
||||
gst_fdsink_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 (&sinktemplate));
|
||||
gst_element_class_set_details (gstelement_class, &gst_fdsink_details);
|
||||
}
|
||||
static void
|
||||
gst_fdsink_class_init (GstFdSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
|
||||
g_param_spec_int ("fd", "fd", "An open file descriptor to write to",
|
||||
0, G_MAXINT, 1, G_PARAM_READWRITE));
|
||||
|
||||
gobject_class->set_property = gst_fdsink_set_property;
|
||||
gobject_class->get_property = gst_fdsink_get_property;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsink_init (GstFdSink * fdsink)
|
||||
{
|
||||
fdsink->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (fdsink), fdsink->sinkpad);
|
||||
gst_pad_set_chain_function (fdsink->sinkpad, gst_fdsink_chain);
|
||||
|
||||
fdsink->fd = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsink_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstFdSink *fdsink;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
fdsink = GST_FDSINK (gst_pad_get_parent (pad));
|
||||
|
||||
g_return_if_fail (fdsink->fd >= 0);
|
||||
|
||||
if (GST_BUFFER_DATA (buf)) {
|
||||
GST_DEBUG ("writing %d bytes to file descriptor %d", GST_BUFFER_SIZE (buf),
|
||||
fdsink->fd);
|
||||
write (fdsink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsink_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFdSink *fdsink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FDSINK (object));
|
||||
|
||||
fdsink = GST_FDSINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_FD:
|
||||
fdsink->fd = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFdSink *fdsink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FDSINK (object));
|
||||
|
||||
fdsink = GST_FDSINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_FD:
|
||||
g_value_set_int (value, fdsink->fd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfdsink.h:
|
||||
*
|
||||
* 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_FDSINK_H__
|
||||
#define __GST_FDSINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_FDSINK \
|
||||
(gst_fdsink_get_type())
|
||||
#define GST_FDSINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FDSINK,GstFdSink))
|
||||
#define GST_FDSINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FDSINK,GstFdSinkClass))
|
||||
#define GST_IS_FDSINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FDSINK))
|
||||
#define GST_IS_FDSINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FDSINK))
|
||||
|
||||
typedef struct _GstFdSink GstFdSink;
|
||||
typedef struct _GstFdSinkClass GstFdSinkClass;
|
||||
|
||||
struct _GstFdSink {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct _GstFdSinkClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_fdsink_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FDSINK_H__ */
|
|
@ -1,396 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfdsrc.c:
|
||||
*
|
||||
* 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_private.h"
|
||||
|
||||
#ifndef HAVE_WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "gstfdsrc.h"
|
||||
|
||||
#define DEFAULT_BLOCKSIZE 4096
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_fdsrc_debug);
|
||||
#define GST_CAT_DEFAULT gst_fdsrc_debug
|
||||
|
||||
GstElementDetails gst_fdsrc_details = GST_ELEMENT_DETAILS ("Disk Source",
|
||||
"Source/File",
|
||||
"Synchronous read from a file",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>");
|
||||
|
||||
|
||||
/* FdSrc signals and args */
|
||||
enum
|
||||
{
|
||||
SIGNAL_TIMEOUT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_FD,
|
||||
ARG_BLOCKSIZE,
|
||||
ARG_TIMEOUT
|
||||
};
|
||||
|
||||
static guint gst_fdsrc_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void gst_fdsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
|
||||
|
||||
static void
|
||||
_do_init (GType fdsrc_type)
|
||||
{
|
||||
static const GInterfaceInfo urihandler_info = {
|
||||
gst_fdsrc_uri_handler_init,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
g_type_add_interface_static (fdsrc_type, GST_TYPE_URI_HANDLER,
|
||||
&urihandler_info);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
|
||||
}
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFdSrc, gst_fdsrc, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static void gst_fdsrc_dispose (GObject * obj);
|
||||
static void gst_fdsrc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fdsrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstElementStateReturn gst_fdsrc_change_state (GstElement * element);
|
||||
static gboolean gst_fdsrc_release_locks (GstElement * element);
|
||||
static GstData *gst_fdsrc_get (GstPad * pad);
|
||||
|
||||
|
||||
static void
|
||||
gst_fdsrc_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 (gstelement_class, &gst_fdsrc_details);
|
||||
}
|
||||
static void
|
||||
gst_fdsrc_class_init (GstFdSrcClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
|
||||
g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
|
||||
0, G_MAXINT, 0, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
|
||||
g_param_spec_ulong ("blocksize", "Block size",
|
||||
"Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TIMEOUT,
|
||||
g_param_spec_uint64 ("timeout", "Timeout", "Read timeout in nanoseconds",
|
||||
0, G_MAXUINT64, 0, G_PARAM_READWRITE));
|
||||
|
||||
gst_fdsrc_signals[SIGNAL_TIMEOUT] =
|
||||
g_signal_new ("timeout", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstFdSrcClass, timeout), NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||
|
||||
gobject_class->set_property = gst_fdsrc_set_property;
|
||||
gobject_class->get_property = gst_fdsrc_get_property;
|
||||
gobject_class->dispose = gst_fdsrc_dispose;
|
||||
|
||||
gstelement_class->change_state = gst_fdsrc_change_state;
|
||||
gstelement_class->release_locks = gst_fdsrc_release_locks;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsrc_dispose (GObject * obj)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (obj);
|
||||
|
||||
g_free (src->uri);
|
||||
src->uri = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsrc_init (GstFdSrc * fdsrc)
|
||||
{
|
||||
fdsrc->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
|
||||
gst_pad_set_get_function (fdsrc->srcpad, gst_fdsrc_get);
|
||||
gst_element_add_pad (GST_ELEMENT (fdsrc), fdsrc->srcpad);
|
||||
|
||||
fdsrc->fd = 0;
|
||||
fdsrc->uri = g_strdup_printf ("fd://%d", fdsrc->fd);
|
||||
fdsrc->curoffset = 0;
|
||||
fdsrc->blocksize = DEFAULT_BLOCKSIZE;
|
||||
fdsrc->timeout = 0;
|
||||
fdsrc->seq = 0;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_fdsrc_change_state (GstElement * element)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (element);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
src->curoffset = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* in any case, an interrupt succeeds if we get here */
|
||||
src->interrupted = FALSE;
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_fdsrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFdSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FDSRC (object));
|
||||
|
||||
src = GST_FDSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_FD:
|
||||
src->fd = g_value_get_int (value);
|
||||
g_free (src->uri);
|
||||
src->uri = g_strdup_printf ("fd://%d", src->fd);
|
||||
break;
|
||||
case ARG_BLOCKSIZE:
|
||||
src->blocksize = g_value_get_ulong (value);
|
||||
break;
|
||||
case ARG_TIMEOUT:
|
||||
src->timeout = g_value_get_uint64 (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFdSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FDSRC (object));
|
||||
|
||||
src = GST_FDSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_BLOCKSIZE:
|
||||
g_value_set_ulong (value, src->blocksize);
|
||||
break;
|
||||
case ARG_FD:
|
||||
g_value_set_int (value, src->fd);
|
||||
break;
|
||||
case ARG_TIMEOUT:
|
||||
g_value_set_uint64 (value, src->timeout);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fdsrc_release_locks (GstElement * element)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (element);
|
||||
|
||||
src->interrupted = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstData *
|
||||
gst_fdsrc_get (GstPad * pad)
|
||||
{
|
||||
GstFdSrc *src;
|
||||
GstBuffer *buf;
|
||||
glong readbytes;
|
||||
|
||||
#ifndef HAVE_WIN32
|
||||
fd_set readfds;
|
||||
struct timeval t;
|
||||
gint retval;
|
||||
#endif
|
||||
|
||||
src = GST_FDSRC (gst_pad_get_parent (pad));
|
||||
|
||||
/* create the buffer */
|
||||
buf = gst_buffer_new_and_alloc (src->blocksize);
|
||||
|
||||
#ifndef HAVE_WIN32
|
||||
FD_ZERO (&readfds);
|
||||
FD_SET (src->fd, &readfds);
|
||||
|
||||
/* loop until data is available, or a timeout is set. Re-enter
|
||||
* loop if we got a timeout without a timeout set, or if we
|
||||
* received an interrupt event. */
|
||||
do {
|
||||
if (src->timeout != 0) {
|
||||
GST_TIME_TO_TIMEVAL (src->timeout, t);
|
||||
} else {
|
||||
GST_TIME_TO_TIMEVAL (1000000000, t);
|
||||
}
|
||||
|
||||
retval = select (src->fd + 1, &readfds, NULL, NULL, &t);
|
||||
} while (!src->interrupted &&
|
||||
((retval == -1 && errno == EINTR) || (retval == 0 && src->timeout == 0)));
|
||||
|
||||
if (src->interrupted) {
|
||||
GST_DEBUG_OBJECT (src, "received interrupt");
|
||||
return GST_DATA (gst_event_new (GST_EVENT_INTERRUPT));
|
||||
} else if (retval == -1) {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
||||
("select on file descriptor: %s.", g_strerror (errno)));
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
} else if (retval == 0) {
|
||||
g_signal_emit (G_OBJECT (src), gst_fdsrc_signals[SIGNAL_TIMEOUT], 0);
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
readbytes = read (src->fd, GST_BUFFER_DATA (buf), src->blocksize);
|
||||
} while (readbytes == -1 && errno == EINTR); /* retry if interrupted */
|
||||
|
||||
if (readbytes > 0) {
|
||||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||
GST_BUFFER_SIZE (buf) = readbytes;
|
||||
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
|
||||
src->curoffset += readbytes;
|
||||
|
||||
/* we're done, return the buffer */
|
||||
return GST_DATA (buf);
|
||||
} else if (readbytes == 0) {
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
||||
("read on file descriptor: %s.", g_strerror (errno)));
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
}
|
||||
}
|
||||
|
||||
/*** GSTURIHANDLER INTERFACE *************************************************/
|
||||
|
||||
static guint
|
||||
gst_fdsrc_uri_get_type (void)
|
||||
{
|
||||
return GST_URI_SRC;
|
||||
}
|
||||
static gchar **
|
||||
gst_fdsrc_uri_get_protocols (void)
|
||||
{
|
||||
static gchar *protocols[] = { "fd", NULL };
|
||||
|
||||
return protocols;
|
||||
}
|
||||
static const gchar *
|
||||
gst_fdsrc_uri_get_uri (GstURIHandler * handler)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (handler);
|
||||
|
||||
return src->uri;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fdsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
|
||||
{
|
||||
gchar *protocol;
|
||||
GstFdSrc *src = GST_FDSRC (handler);
|
||||
gint fd = src->fd;
|
||||
|
||||
protocol = gst_uri_get_protocol (uri);
|
||||
if (strcmp (protocol, "fd") != 0) {
|
||||
g_free (protocol);
|
||||
return FALSE;
|
||||
}
|
||||
g_free (protocol);
|
||||
sscanf (uri, "fd://%d", &fd);
|
||||
src->fd = fd;
|
||||
g_free (src->uri);
|
||||
src->uri = g_strdup (uri);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
|
||||
{
|
||||
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
|
||||
|
||||
iface->get_type = gst_fdsrc_uri_get_type;
|
||||
iface->get_protocols = gst_fdsrc_uri_get_protocols;
|
||||
iface->get_uri = gst_fdsrc_uri_get_uri;
|
||||
iface->set_uri = gst_fdsrc_uri_set_uri;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfdsrc.h:
|
||||
*
|
||||
* 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_FDSRC_H__
|
||||
#define __GST_FDSRC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_FDSRC \
|
||||
(gst_fdsrc_get_type())
|
||||
#define GST_FDSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FDSRC,GstFdSrc))
|
||||
#define GST_FDSRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FDSRC,GstFdSrcClass))
|
||||
#define GST_IS_FDSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FDSRC))
|
||||
#define GST_IS_FDSRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FDSRC))
|
||||
|
||||
|
||||
typedef struct _GstFdSrc GstFdSrc;
|
||||
typedef struct _GstFdSrcClass GstFdSrcClass;
|
||||
|
||||
struct _GstFdSrc {
|
||||
GstElement element;
|
||||
/* pads */
|
||||
GstPad *srcpad;
|
||||
|
||||
/* fd */
|
||||
gint fd;
|
||||
gboolean interrupted;
|
||||
gchar *uri;
|
||||
|
||||
gulong curoffset; /* current offset in file */
|
||||
gulong blocksize; /* bytes per read */
|
||||
guint64 timeout; /* read timeout, in nanoseconds */
|
||||
|
||||
gulong seq; /* buffer sequence number */
|
||||
};
|
||||
|
||||
struct _GstFdSrcClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*timeout) (GstElement *element);
|
||||
};
|
||||
|
||||
GType gst_fdsrc_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FDSRC_H__ */
|
|
@ -1,546 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfilesink.c:
|
||||
*
|
||||
* 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-i18n-lib.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <errno.h>
|
||||
#include "gstfilesink.h"
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_filesink_debug);
|
||||
#define GST_CAT_DEFAULT gst_filesink_debug
|
||||
|
||||
GstElementDetails gst_filesink_details = GST_ELEMENT_DETAILS ("File Sink",
|
||||
"Sink/File",
|
||||
"Write stream to a file",
|
||||
"Thomas <thomas@apestaart.org>");
|
||||
|
||||
|
||||
/* FileSink signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
SIGNAL_HANDOFF,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_LOCATION
|
||||
};
|
||||
|
||||
static const GstFormat *
|
||||
gst_filesink_get_formats (GstPad * pad)
|
||||
{
|
||||
static const GstFormat formats[] = {
|
||||
GST_FORMAT_BYTES,
|
||||
0,
|
||||
};
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
static const GstQueryType *
|
||||
gst_filesink_get_query_types (GstPad * pad)
|
||||
{
|
||||
static const GstQueryType types[] = {
|
||||
GST_QUERY_TOTAL,
|
||||
GST_QUERY_POSITION,
|
||||
0
|
||||
};
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
static void gst_filesink_dispose (GObject * object);
|
||||
|
||||
static void gst_filesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_filesink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static gboolean gst_filesink_open_file (GstFileSink * sink);
|
||||
static void gst_filesink_close_file (GstFileSink * sink);
|
||||
|
||||
static gboolean gst_filesink_handle_event (GstPad * pad, GstEvent * event);
|
||||
static gboolean gst_filesink_pad_query (GstPad * pad, GstQueryType type,
|
||||
GstFormat * format, gint64 * value);
|
||||
static void gst_filesink_chain (GstPad * pad, GstData * _data);
|
||||
|
||||
static void gst_filesink_uri_handler_init (gpointer g_iface,
|
||||
gpointer iface_data);
|
||||
|
||||
static GstElementStateReturn gst_filesink_change_state (GstElement * element);
|
||||
|
||||
static guint gst_filesink_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
_do_init (GType filesink_type)
|
||||
{
|
||||
static const GInterfaceInfo urihandler_info = {
|
||||
gst_filesink_uri_handler_init,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
g_type_add_interface_static (filesink_type, GST_TYPE_URI_HANDLER,
|
||||
&urihandler_info);
|
||||
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0,
|
||||
"filesink element");
|
||||
}
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
|
||||
static void
|
||||
gst_filesink_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
gstelement_class->change_state = gst_filesink_change_state;
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sinktemplate));
|
||||
gst_element_class_set_details (gstelement_class, &gst_filesink_details);
|
||||
}
|
||||
static void
|
||||
gst_filesink_class_init (GstFileSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
|
||||
g_param_spec_string ("location", "File Location",
|
||||
"Location of the file to write", NULL, G_PARAM_READWRITE));
|
||||
|
||||
gst_filesink_signals[SIGNAL_HANDOFF] =
|
||||
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstFileSinkClass, handoff), NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||
|
||||
gobject_class->set_property = gst_filesink_set_property;
|
||||
gobject_class->get_property = gst_filesink_get_property;
|
||||
gobject_class->dispose = gst_filesink_dispose;
|
||||
}
|
||||
static void
|
||||
gst_filesink_init (GstFileSink * filesink)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (filesink), pad);
|
||||
gst_pad_set_chain_function (pad, gst_filesink_chain);
|
||||
|
||||
GST_FLAG_SET (GST_ELEMENT (filesink), GST_ELEMENT_EVENT_AWARE);
|
||||
|
||||
gst_pad_set_query_function (pad, gst_filesink_pad_query);
|
||||
gst_pad_set_query_type_function (pad, gst_filesink_get_query_types);
|
||||
gst_pad_set_formats_function (pad, gst_filesink_get_formats);
|
||||
|
||||
filesink->filename = NULL;
|
||||
filesink->file = NULL;
|
||||
}
|
||||
static void
|
||||
gst_filesink_dispose (GObject * object)
|
||||
{
|
||||
GstFileSink *sink = GST_FILESINK (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
|
||||
g_free (sink->uri);
|
||||
sink->uri = NULL;
|
||||
g_free (sink->filename);
|
||||
sink->filename = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_filesink_set_location (GstFileSink * sink, const gchar * location)
|
||||
{
|
||||
/* the element must be stopped or paused in order to do this */
|
||||
if (GST_STATE (sink) > GST_STATE_PAUSED)
|
||||
return FALSE;
|
||||
if (GST_STATE (sink) == GST_STATE_PAUSED &&
|
||||
GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN))
|
||||
return FALSE;
|
||||
|
||||
g_free (sink->filename);
|
||||
g_free (sink->uri);
|
||||
if (location != NULL) {
|
||||
sink->filename = g_strdup (location);
|
||||
sink->uri = gst_uri_construct ("file", location);
|
||||
} else {
|
||||
sink->filename = NULL;
|
||||
sink->uri = NULL;
|
||||
}
|
||||
|
||||
if (GST_STATE (sink) == GST_STATE_PAUSED)
|
||||
gst_filesink_open_file (sink);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
static void
|
||||
gst_filesink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstFileSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
sink = GST_FILESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOCATION:
|
||||
gst_filesink_set_location (sink, g_value_get_string (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_filesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFileSink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_FILESINK (object));
|
||||
|
||||
sink = GST_FILESINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOCATION:
|
||||
g_value_set_string (value, sink->filename);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_filesink_open_file (GstFileSink * sink)
|
||||
{
|
||||
g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE);
|
||||
|
||||
/* open the file */
|
||||
if (sink->filename == NULL || sink->filename[0] == '\0') {
|
||||
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
|
||||
(_("No file name specified for writing.")), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sink->file = fopen (sink->filename, "wb");
|
||||
if (sink->file == NULL) {
|
||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||
(_("Could not open file \"%s\" for writing."), sink->filename),
|
||||
GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_FLAG_SET (sink, GST_FILESINK_OPEN);
|
||||
|
||||
sink->data_written = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_filesink_close_file (GstFileSink * sink)
|
||||
{
|
||||
g_return_if_fail (GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN));
|
||||
|
||||
if (fclose (sink->file) != 0) {
|
||||
GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
|
||||
(_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM);
|
||||
} else {
|
||||
GST_FLAG_UNSET (sink, GST_FILESINK_OPEN);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_filesink_pad_query (GstPad * pad, GstQueryType type,
|
||||
GstFormat * format, gint64 * value)
|
||||
{
|
||||
GstFileSink *sink = GST_FILESINK (GST_PAD_PARENT (pad));
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_TOTAL:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) {
|
||||
*value = sink->data_written; /* FIXME - doesn't the kernel provide
|
||||
such a function? */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case GST_QUERY_POSITION:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) {
|
||||
*value = ftell (sink->file);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* handle events (search) */
|
||||
static gboolean
|
||||
gst_filesink_handle_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstEventType type;
|
||||
GstFileSink *filesink;
|
||||
|
||||
filesink = GST_FILESINK (gst_pad_get_parent (pad));
|
||||
|
||||
if (!(GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN))) {
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
|
||||
|
||||
switch (type) {
|
||||
case GST_EVENT_SEEK:
|
||||
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
|
||||
if (fflush (filesink->file)) {
|
||||
gst_event_unref (event);
|
||||
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
|
||||
(_("Error while writing to file \"%s\"."), filesink->filename),
|
||||
GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (GST_EVENT_SEEK_METHOD (event)) {
|
||||
case GST_SEEK_METHOD_SET:
|
||||
fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_SET);
|
||||
break;
|
||||
case GST_SEEK_METHOD_CUR:
|
||||
fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_CUR);
|
||||
break;
|
||||
case GST_SEEK_METHOD_END:
|
||||
fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_END);
|
||||
break;
|
||||
default:
|
||||
g_warning ("unknown seek method!");
|
||||
break;
|
||||
}
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
{
|
||||
gint64 offset;
|
||||
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset))
|
||||
fseek (filesink->file, offset, SEEK_SET);
|
||||
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_FLUSH:
|
||||
if (fflush (filesink->file)) {
|
||||
gst_event_unref (event);
|
||||
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
|
||||
(_("Error while writing to file \"%s\"."), filesink->filename),
|
||||
GST_ERROR_SYSTEM);
|
||||
}
|
||||
break;
|
||||
case GST_EVENT_EOS:
|
||||
gst_event_unref (event);
|
||||
gst_filesink_close_file (filesink);
|
||||
gst_element_set_eos (GST_ELEMENT (filesink));
|
||||
break;
|
||||
default:
|
||||
gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_filesink_chain:
|
||||
* @pad: the pad this filesink is connected to
|
||||
* @buf: the buffer that has to be absorbed
|
||||
*
|
||||
* take the buffer from the pad and write to file if it's open
|
||||
*/
|
||||
static void
|
||||
gst_filesink_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstFileSink *filesink;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
filesink = GST_FILESINK (gst_pad_get_parent (pad));
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
gst_filesink_handle_event (pad, GST_EVENT (buf));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN)) {
|
||||
guint bytes_written = 0, back_pending = 0;
|
||||
|
||||
if (ftell (filesink->file) < filesink->data_written)
|
||||
back_pending = filesink->data_written - ftell (filesink->file);
|
||||
while (bytes_written < GST_BUFFER_SIZE (buf)) {
|
||||
size_t wrote = fwrite (GST_BUFFER_DATA (buf) + bytes_written, 1,
|
||||
GST_BUFFER_SIZE (buf) - bytes_written,
|
||||
filesink->file);
|
||||
|
||||
if (wrote <= 0) {
|
||||
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
|
||||
(_("Error while writing to file \"%s\"."), filesink->filename),
|
||||
("Only %d of %d bytes written: %s",
|
||||
bytes_written, GST_BUFFER_SIZE (buf), strerror (errno)));
|
||||
break;
|
||||
}
|
||||
bytes_written += wrote;
|
||||
}
|
||||
|
||||
filesink->data_written += bytes_written - back_pending;
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
g_signal_emit (G_OBJECT (filesink),
|
||||
gst_filesink_signals[SIGNAL_HANDOFF], 0, filesink);
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_filesink_change_state (GstElement * element)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN))
|
||||
gst_filesink_close_file (GST_FILESINK (element));
|
||||
break;
|
||||
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) {
|
||||
if (!gst_filesink_open_file (GST_FILESINK (element)))
|
||||
return GST_STATE_FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/*** GSTURIHANDLER INTERFACE *************************************************/
|
||||
|
||||
static guint
|
||||
gst_filesink_uri_get_type (void)
|
||||
{
|
||||
return GST_URI_SINK;
|
||||
}
|
||||
static gchar **
|
||||
gst_filesink_uri_get_protocols (void)
|
||||
{
|
||||
static gchar *protocols[] = { "file", NULL };
|
||||
|
||||
return protocols;
|
||||
}
|
||||
static const gchar *
|
||||
gst_filesink_uri_get_uri (GstURIHandler * handler)
|
||||
{
|
||||
GstFileSink *sink = GST_FILESINK (handler);
|
||||
|
||||
return sink->uri;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_filesink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
|
||||
{
|
||||
gchar *protocol, *location;
|
||||
gboolean ret;
|
||||
GstFileSink *sink = GST_FILESINK (handler);
|
||||
|
||||
protocol = gst_uri_get_protocol (uri);
|
||||
if (strcmp (protocol, "file") != 0) {
|
||||
g_free (protocol);
|
||||
return FALSE;
|
||||
}
|
||||
g_free (protocol);
|
||||
location = gst_uri_get_location (uri);
|
||||
ret = gst_filesink_set_location (sink, location);
|
||||
g_free (location);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_filesink_uri_handler_init (gpointer g_iface, gpointer iface_data)
|
||||
{
|
||||
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
|
||||
|
||||
iface->get_type = gst_filesink_uri_get_type;
|
||||
iface->get_protocols = gst_filesink_uri_get_protocols;
|
||||
iface->get_uri = gst_filesink_uri_get_uri;
|
||||
iface->set_uri = gst_filesink_uri_set_uri;
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfilesink.h:
|
||||
*
|
||||
* 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_FILESINK_H__
|
||||
#define __GST_FILESINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_FILESINK \
|
||||
(gst_filesink_get_type())
|
||||
#define GST_FILESINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FILESINK,GstFileSink))
|
||||
#define GST_FILESINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FILESINK,GstFileSinkClass))
|
||||
#define GST_IS_FILESINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FILESINK))
|
||||
#define GST_IS_FILESINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILESINK))
|
||||
|
||||
typedef struct _GstFileSink GstFileSink;
|
||||
typedef struct _GstFileSinkClass GstFileSinkClass;
|
||||
|
||||
typedef enum {
|
||||
GST_FILESINK_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_FILESINK_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
|
||||
} GstFileSinkFlags;
|
||||
|
||||
struct _GstFileSink {
|
||||
GstElement element;
|
||||
|
||||
gchar *filename;
|
||||
gchar *uri;
|
||||
FILE *file;
|
||||
|
||||
guint64 data_written;
|
||||
};
|
||||
|
||||
struct _GstFileSinkClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstPad *pad);
|
||||
};
|
||||
|
||||
GType gst_filesink_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FILESINK_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,88 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstfilesrc.h:
|
||||
*
|
||||
* 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_FILESRC_H__
|
||||
#define __GST_FILESRC_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_FILESRC \
|
||||
(gst_filesrc_get_type())
|
||||
#define GST_FILESRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FILESRC,GstFileSrc))
|
||||
#define GST_FILESRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FILESRC,GstFileSrcClass))
|
||||
#define GST_IS_FILESRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FILESRC))
|
||||
#define GST_IS_FILESRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILESRC))
|
||||
|
||||
typedef enum {
|
||||
GST_FILESRC_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_FILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
|
||||
} GstFileSrcFlags;
|
||||
|
||||
typedef struct _GstFileSrc GstFileSrc;
|
||||
typedef struct _GstFileSrcClass GstFileSrcClass;
|
||||
|
||||
struct _GstFileSrc {
|
||||
GstElement element;
|
||||
GstPad *srcpad;
|
||||
|
||||
guint pagesize; /* system page size*/
|
||||
|
||||
gchar *filename; /* filename */
|
||||
gchar *uri; /* caching the URI */
|
||||
gint fd; /* open file descriptor*/
|
||||
off_t filelen; /* what's the file length?*/
|
||||
|
||||
off_t curoffset; /* current offset in file*/
|
||||
off_t lastoffset; /* last offset seen in file*/
|
||||
off_t block_size; /* bytes per read */
|
||||
gboolean touch; /* whether to touch every page */
|
||||
gboolean using_mmap; /* whether we opened it with mmap */
|
||||
gboolean is_regular; /* whether it's (symlink to)
|
||||
a regular file */
|
||||
|
||||
GstBuffer *mapbuf;
|
||||
size_t mapsize;
|
||||
|
||||
gint need_discont;
|
||||
gboolean need_flush;
|
||||
};
|
||||
|
||||
struct _GstFileSrcClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_filesrc_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FILESRC_H__ */
|
|
@ -1,544 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstidentity.c:
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "../gst-i18n-lib.h"
|
||||
#include "gstidentity.h"
|
||||
#include <gst/gstmarshal.h>
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_identity_debug);
|
||||
#define GST_CAT_DEFAULT gst_identity_debug
|
||||
|
||||
GstElementDetails gst_identity_details = GST_ELEMENT_DETAILS ("Identity",
|
||||
"Generic",
|
||||
"Pass data without modification",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>");
|
||||
|
||||
|
||||
/* Identity signals and args */
|
||||
enum
|
||||
{
|
||||
SIGNAL_HANDOFF,
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define DEFAULT_LOOP_BASED FALSE
|
||||
#define DEFAULT_SLEEP_TIME 0
|
||||
#define DEFAULT_DUPLICATE 1
|
||||
#define DEFAULT_ERROR_AFTER -1
|
||||
#define DEFAULT_DROP_PROBABILITY 0.0
|
||||
#define DEFAULT_DATARATE 0
|
||||
#define DEFAULT_SILENT FALSE
|
||||
#define DEFAULT_DUMP FALSE
|
||||
#define DEFAULT_SYNC FALSE
|
||||
#define DEFAULT_CHECK_PERFECT FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_LOOP_BASED,
|
||||
ARG_SLEEP_TIME,
|
||||
ARG_DUPLICATE,
|
||||
ARG_ERROR_AFTER,
|
||||
ARG_DROP_PROBABILITY,
|
||||
ARG_DATARATE,
|
||||
ARG_SILENT,
|
||||
ARG_LAST_MESSAGE,
|
||||
ARG_DUMP,
|
||||
ARG_SYNC,
|
||||
ARG_CHECK_PERFECT
|
||||
};
|
||||
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static void gst_identity_finalize (GObject * object);
|
||||
static void gst_identity_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_identity_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static GstElementStateReturn gst_identity_change_state (GstElement * element);
|
||||
|
||||
static void gst_identity_chain (GstPad * pad, GstData * _data);
|
||||
static void gst_identity_set_clock (GstElement * element, GstClock * clock);
|
||||
|
||||
|
||||
static guint gst_identity_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gst_identity_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 (gstelement_class, &gst_identity_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_finalize (GObject * object)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
|
||||
identity = GST_IDENTITY (object);
|
||||
|
||||
g_free (identity->last_message);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_class_init (GstIdentityClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
|
||||
g_param_spec_boolean ("loop-based", "Loop-based",
|
||||
"Set to TRUE to use loop-based rather than chain-based scheduling",
|
||||
DEFAULT_LOOP_BASED, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLEEP_TIME,
|
||||
g_param_spec_uint ("sleep-time", "Sleep time",
|
||||
"Microseconds to sleep between processing", 0, G_MAXUINT,
|
||||
DEFAULT_SLEEP_TIME, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUPLICATE,
|
||||
g_param_spec_uint ("duplicate", "Duplicate Buffers",
|
||||
"Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ERROR_AFTER,
|
||||
g_param_spec_int ("error_after", "Error After", "Error after N buffers",
|
||||
G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DROP_PROBABILITY,
|
||||
g_param_spec_float ("drop_probability", "Drop Probability",
|
||||
"The Probability a buffer is dropped", 0.0, 1.0,
|
||||
DEFAULT_DROP_PROBABILITY, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATARATE,
|
||||
g_param_spec_int ("datarate", "Datarate",
|
||||
"(Re)timestamps buffers with number of bytes per second (0 = inactive)",
|
||||
0, G_MAXINT, DEFAULT_DATARATE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent", DEFAULT_SILENT,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last-message", "last-message", "last-message", NULL,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump buffer contents",
|
||||
DEFAULT_DUMP, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
|
||||
g_param_spec_boolean ("sync", "Synchronize",
|
||||
"Synchronize to pipeline clock", DEFAULT_SYNC, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CHECK_PERFECT,
|
||||
g_param_spec_boolean ("check-perfect", "Check For Perfect Stream",
|
||||
"Verify that the stream is time- and data-contiguous",
|
||||
DEFAULT_CHECK_PERFECT, G_PARAM_READWRITE));
|
||||
|
||||
gst_identity_signals[SIGNAL_HANDOFF] =
|
||||
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstIdentityClass, handoff), NULL, NULL,
|
||||
gst_marshal_VOID__BOXED, G_TYPE_NONE, 1,
|
||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
|
||||
|
||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_identity_change_state);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_init (GstIdentity * identity)
|
||||
{
|
||||
identity->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
|
||||
gst_pad_set_chain_function (identity->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_identity_chain));
|
||||
gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
|
||||
gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
|
||||
|
||||
identity->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
|
||||
gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
|
||||
gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
|
||||
|
||||
identity->loop_based = DEFAULT_LOOP_BASED;
|
||||
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
||||
identity->duplicate = DEFAULT_DUPLICATE;
|
||||
identity->error_after = DEFAULT_ERROR_AFTER;
|
||||
identity->drop_probability = DEFAULT_DROP_PROBABILITY;
|
||||
identity->datarate = DEFAULT_DATARATE;
|
||||
identity->silent = DEFAULT_SILENT;
|
||||
identity->sync = DEFAULT_SYNC;
|
||||
identity->check_perfect = DEFAULT_CHECK_PERFECT;
|
||||
identity->dump = DEFAULT_DUMP;
|
||||
identity->last_message = NULL;
|
||||
identity->srccaps = NULL;
|
||||
|
||||
GST_FLAG_SET (identity, GST_ELEMENT_EVENT_AWARE);
|
||||
GST_FLAG_SET (identity, GST_ELEMENT_WORK_IN_PLACE);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstIdentity *identity = GST_IDENTITY (element);
|
||||
|
||||
gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_identity_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstIdentity *identity;
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
identity = GST_IDENTITY (gst_pad_get_parent (pad));
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GstEvent *event = GST_EVENT (buf);
|
||||
|
||||
if (!identity->silent) {
|
||||
g_free (identity->last_message);
|
||||
|
||||
identity->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||
|
||||
g_object_notify (G_OBJECT (identity), "last_message");
|
||||
}
|
||||
gst_pad_event_default (pad, event);
|
||||
return;
|
||||
}
|
||||
|
||||
/* see if we need to do perfect stream checking */
|
||||
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
|
||||
if (identity->check_perfect &&
|
||||
GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
|
||||
/* check if we had a previous buffer to compare to */
|
||||
if (identity->prev_timestamp != GST_CLOCK_TIME_NONE) {
|
||||
if (identity->prev_timestamp + identity->prev_duration !=
|
||||
GST_BUFFER_TIMESTAMP (buf)) {
|
||||
GST_WARNING_OBJECT (identity,
|
||||
"Buffer not time-contiguous with previous one: " "prev ts %"
|
||||
GST_TIME_FORMAT ", prev dur %" GST_TIME_FORMAT ", new ts %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (identity->prev_timestamp),
|
||||
GST_TIME_ARGS (identity->prev_duration),
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||
}
|
||||
if (identity->prev_offset_end != GST_BUFFER_OFFSET (buf)) {
|
||||
GST_WARNING_OBJECT (identity,
|
||||
"Buffer not data-contiguous with previous one: "
|
||||
"prev offset_end %" G_GINT64_FORMAT ", new offset %"
|
||||
G_GINT64_FORMAT, identity->prev_offset_end,
|
||||
GST_BUFFER_OFFSET (buf));
|
||||
}
|
||||
}
|
||||
/* update prev values */
|
||||
identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf);
|
||||
identity->prev_duration = GST_BUFFER_DURATION (buf);
|
||||
identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf);
|
||||
}
|
||||
|
||||
if (identity->error_after >= 0) {
|
||||
identity->error_after--;
|
||||
if (identity->error_after == 0) {
|
||||
gst_buffer_unref (buf);
|
||||
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
||||
(_("Failed after iterations as requested.")), (NULL));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (identity->drop_probability > 0.0) {
|
||||
if ((gfloat) (1.0 * rand () / (RAND_MAX)) < identity->drop_probability) {
|
||||
g_free (identity->last_message);
|
||||
identity->last_message =
|
||||
g_strdup_printf ("dropping ******* (%s:%s)i (%d bytes, timestamp: %"
|
||||
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
|
||||
G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (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_FLAGS (buf), buf);
|
||||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
gst_buffer_unref (buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (identity->dump) {
|
||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
for (i = identity->duplicate; i; i--) {
|
||||
GstClockTime time;
|
||||
|
||||
if (!identity->silent) {
|
||||
g_free (identity->last_message);
|
||||
identity->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %"
|
||||
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
|
||||
G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
|
||||
GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (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_FLAGS (buf), buf);
|
||||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
}
|
||||
|
||||
time = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
if (identity->datarate > 0) {
|
||||
time = identity->bytes_handled * GST_SECOND / identity->datarate;
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) = time;
|
||||
GST_BUFFER_DURATION (buf) =
|
||||
GST_BUFFER_SIZE (buf) * GST_SECOND / identity->datarate;
|
||||
}
|
||||
|
||||
g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
|
||||
buf);
|
||||
|
||||
if (i > 1)
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
if (identity->sync) {
|
||||
if (identity->clock) {
|
||||
gst_element_wait (GST_ELEMENT (identity), time);
|
||||
}
|
||||
}
|
||||
|
||||
identity->bytes_handled += GST_BUFFER_SIZE (buf);
|
||||
gst_pad_push (identity->srcpad, GST_DATA (buf));
|
||||
|
||||
if (identity->sleep_time)
|
||||
g_usleep (identity->sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_loop (GstElement * element)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
GstBuffer *buf;
|
||||
|
||||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_IDENTITY (element));
|
||||
|
||||
identity = GST_IDENTITY (element);
|
||||
|
||||
buf = GST_BUFFER (gst_pad_pull (identity->sinkpad));
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GstEvent *event = GST_EVENT (buf);
|
||||
|
||||
if (GST_EVENT_IS_INTERRUPT (event)) {
|
||||
gst_event_unref (event);
|
||||
} else {
|
||||
gst_pad_event_default (identity->sinkpad, event);
|
||||
}
|
||||
} else {
|
||||
gst_identity_chain (identity->sinkpad, GST_DATA (buf));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_IDENTITY (object));
|
||||
|
||||
identity = GST_IDENTITY (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOOP_BASED:
|
||||
identity->loop_based = g_value_get_boolean (value);
|
||||
if (identity->loop_based) {
|
||||
gst_element_set_loop_function (GST_ELEMENT (identity),
|
||||
gst_identity_loop);
|
||||
gst_pad_set_chain_function (identity->sinkpad, NULL);
|
||||
} else {
|
||||
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
|
||||
gst_element_set_loop_function (GST_ELEMENT (identity), NULL);
|
||||
}
|
||||
break;
|
||||
case ARG_SLEEP_TIME:
|
||||
identity->sleep_time = g_value_get_uint (value);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
identity->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_DUPLICATE:
|
||||
identity->duplicate = g_value_get_uint (value);
|
||||
break;
|
||||
case ARG_DUMP:
|
||||
identity->dump = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_ERROR_AFTER:
|
||||
identity->error_after = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_DROP_PROBABILITY:
|
||||
identity->drop_probability = g_value_get_float (value);
|
||||
break;
|
||||
case ARG_DATARATE:
|
||||
identity->datarate = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_SYNC:
|
||||
identity->sync = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_CHECK_PERFECT:
|
||||
identity->check_perfect = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_IDENTITY (object));
|
||||
|
||||
identity = GST_IDENTITY (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOOP_BASED:
|
||||
g_value_set_boolean (value, identity->loop_based);
|
||||
break;
|
||||
case ARG_SLEEP_TIME:
|
||||
g_value_set_uint (value, identity->sleep_time);
|
||||
break;
|
||||
case ARG_DUPLICATE:
|
||||
g_value_set_uint (value, identity->duplicate);
|
||||
break;
|
||||
case ARG_ERROR_AFTER:
|
||||
g_value_set_int (value, identity->error_after);
|
||||
break;
|
||||
case ARG_DROP_PROBABILITY:
|
||||
g_value_set_float (value, identity->drop_probability);
|
||||
break;
|
||||
case ARG_DATARATE:
|
||||
g_value_set_int (value, identity->datarate);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, identity->silent);
|
||||
break;
|
||||
case ARG_DUMP:
|
||||
g_value_set_boolean (value, identity->dump);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
g_value_set_string (value, identity->last_message);
|
||||
break;
|
||||
case ARG_SYNC:
|
||||
g_value_set_boolean (value, identity->sync);
|
||||
break;
|
||||
case ARG_CHECK_PERFECT:
|
||||
g_value_set_boolean (value, identity->check_perfect);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_identity_change_state (GstElement * element)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
|
||||
g_return_val_if_fail (GST_IS_IDENTITY (element), GST_STATE_FAILURE);
|
||||
|
||||
identity = GST_IDENTITY (element);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
identity->bytes_handled = 0;
|
||||
identity->prev_timestamp = GST_CLOCK_TIME_NONE;
|
||||
identity->prev_duration = GST_CLOCK_TIME_NONE;
|
||||
identity->prev_offset_end = -1;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
g_free (identity->last_message);
|
||||
identity->last_message = NULL;
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstidentity.h:
|
||||
*
|
||||
* 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_IDENTITY_H__
|
||||
#define __GST_IDENTITY_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_IDENTITY \
|
||||
(gst_identity_get_type())
|
||||
#define GST_IDENTITY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IDENTITY,GstIdentity))
|
||||
#define GST_IDENTITY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IDENTITY,GstIdentityClass))
|
||||
#define GST_IS_IDENTITY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IDENTITY))
|
||||
#define GST_IS_IDENTITY_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IDENTITY))
|
||||
|
||||
typedef struct _GstIdentity GstIdentity;
|
||||
typedef struct _GstIdentityClass GstIdentityClass;
|
||||
|
||||
struct _GstIdentity {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
gboolean loop_based;
|
||||
guint duplicate;
|
||||
gint error_after;
|
||||
gfloat drop_probability;
|
||||
gint datarate;
|
||||
guint sleep_time;
|
||||
gboolean silent;
|
||||
gboolean dump;
|
||||
gboolean sync;
|
||||
gboolean check_perfect;
|
||||
GstClockTime prev_timestamp;
|
||||
GstClockTime prev_duration;
|
||||
guint64 prev_offset_end;
|
||||
GstClock *clock;
|
||||
gchar *last_message;
|
||||
GstCaps *srccaps;
|
||||
|
||||
guint64 bytes_handled;
|
||||
};
|
||||
|
||||
struct _GstIdentityClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf);
|
||||
};
|
||||
|
||||
GType gst_identity_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_IDENTITY_H__ */
|
|
@ -1,498 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2002 Wim Taymans <wim.taymans@chello.be>
|
||||
*
|
||||
* gstmd5sink.c: A sink computing an md5 checksum from a stream
|
||||
*
|
||||
* The md5 code was taken from glibc-2.2.3/crypt/md5.c and slightly
|
||||
* modified.
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "gstmd5sink.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_md5sink_debug);
|
||||
#define GST_CAT_DEFAULT gst_md5sink_debug
|
||||
|
||||
GstElementDetails gst_md5sink_details = GST_ELEMENT_DETAILS ("MD5 Sink",
|
||||
"Sink",
|
||||
"compute MD5 for incoming data",
|
||||
"Benjamin Otte <in7y118@public.uni-hamburg.de>");
|
||||
|
||||
/* MD5Sink signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_MD5
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
GstStaticPadTemplate md5_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstMD5Sink, gst_md5sink, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
/* GObject stuff */
|
||||
/*static void gst_md5sink_set_property (GObject *object, guint prop_id,
|
||||
const GValue *value, GParamSpec *pspec);*/
|
||||
static void gst_md5sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_md5sink_chain (GstPad * pad, GstData * _data);
|
||||
static GstElementStateReturn gst_md5sink_change_state (GstElement * element);
|
||||
|
||||
|
||||
/* MD5 stuff */
|
||||
static void md5_init_ctx (GstMD5Sink * ctx);
|
||||
static gpointer md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf);
|
||||
static gpointer md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf);
|
||||
static void md5_process_bytes (const void *buffer, size_t len,
|
||||
GstMD5Sink * ctx);
|
||||
static void md5_process_block (const void *buffer, size_t len,
|
||||
GstMD5Sink * ctx);
|
||||
|
||||
/* This array contains the bytes used to pad the buffer to the next
|
||||
64-byte boundary. (RFC 1321, 3.1: Step 1) */
|
||||
static const guchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
|
||||
|
||||
/* MD5 functions */
|
||||
/* Initialize structure containing state of computation.
|
||||
(RFC 1321, 3.3: Step 3) */
|
||||
static void
|
||||
md5_init_ctx (GstMD5Sink * ctx)
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
ctx->B = 0xefcdab89;
|
||||
ctx->C = 0x98badcfe;
|
||||
ctx->D = 0x10325476;
|
||||
|
||||
ctx->total[0] = ctx->total[1] = 0;
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
|
||||
/* Process the remaining bytes in the internal buffer and the usual
|
||||
prolog according to the standard and write the result to RESBUF.
|
||||
|
||||
IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
aligned for a 32 bits value. */
|
||||
static gpointer
|
||||
md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf)
|
||||
{
|
||||
/* Take yet unprocessed bytes into account. */
|
||||
guint32 bytes = ctx->buflen;
|
||||
size_t pad;
|
||||
|
||||
/* Now count remaining bytes. */
|
||||
ctx->total[0] += bytes;
|
||||
if (ctx->total[0] < bytes)
|
||||
++ctx->total[1];
|
||||
|
||||
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
|
||||
memcpy (&ctx->buffer[bytes], fillbuf, pad);
|
||||
|
||||
/* Put the 64-bit file length in *bits* at the end of the buffer. */
|
||||
*(guint32 *) & ctx->buffer[bytes + pad] = GUINT32_TO_LE (ctx->total[0] << 3);
|
||||
*(guint32 *) & ctx->buffer[bytes + pad + 4] =
|
||||
GUINT32_TO_LE ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
|
||||
|
||||
/* Process last bytes. */
|
||||
md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
|
||||
|
||||
return md5_read_ctx (ctx, resbuf);
|
||||
}
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result
|
||||
must be in little endian byte order.
|
||||
|
||||
IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
aligned for a 32 bits value. */
|
||||
static gpointer
|
||||
md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf)
|
||||
{
|
||||
((guint32 *) resbuf)[0] = GUINT32_TO_LE (ctx->A);
|
||||
((guint32 *) resbuf)[1] = GUINT32_TO_LE (ctx->B);
|
||||
((guint32 *) resbuf)[2] = GUINT32_TO_LE (ctx->C);
|
||||
((guint32 *) resbuf)[3] = GUINT32_TO_LE (ctx->D);
|
||||
|
||||
return resbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
md5_process_bytes (const void *buffer, size_t len, GstMD5Sink * ctx)
|
||||
{
|
||||
/*const void aligned_buffer = buffer; */
|
||||
|
||||
/* When we already have some bits in our internal buffer concatenate
|
||||
both inputs first. */
|
||||
if (ctx->buflen != 0) {
|
||||
size_t left_over = ctx->buflen;
|
||||
size_t add = 128 - left_over > len ? len : 128 - left_over;
|
||||
|
||||
/* Only put full words in the buffer. */
|
||||
/* Forcing alignment here appears to be only an optimization.
|
||||
* The glibc source uses __alignof__, which seems to be a
|
||||
* gratuitous usage of a GCC extension, when sizeof() will
|
||||
* work fine. (And don't question the sanity of using
|
||||
* sizeof(guint32) instead of 4. */
|
||||
/* add -= add % __alignof__ (guint32); */
|
||||
add -= add % sizeof (guint32);
|
||||
|
||||
memcpy (&ctx->buffer[left_over], buffer, add);
|
||||
ctx->buflen += add;
|
||||
|
||||
if (ctx->buflen > 64) {
|
||||
md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
|
||||
|
||||
ctx->buflen &= 63;
|
||||
/* The regions in the following copy operation cannot overlap. */
|
||||
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
|
||||
}
|
||||
|
||||
buffer = (const char *) buffer + add;
|
||||
len -= add;
|
||||
}
|
||||
|
||||
/* Process available complete blocks. */
|
||||
if (len > 64) {
|
||||
md5_process_block (buffer, len & ~63, ctx);
|
||||
buffer = (const char *) buffer + (len & ~63);
|
||||
len &= 63;
|
||||
}
|
||||
|
||||
/* Move remaining bytes in internal buffer. */
|
||||
if (len > 0) {
|
||||
size_t left_over = ctx->buflen;
|
||||
|
||||
memcpy (&ctx->buffer[left_over], buffer, len);
|
||||
left_over += len;
|
||||
if (left_over >= 64) {
|
||||
md5_process_block (ctx->buffer, 64, ctx);
|
||||
left_over -= 64;
|
||||
memcpy (ctx->buffer, &ctx->buffer[64], left_over);
|
||||
}
|
||||
ctx->buflen = left_over;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* These are the four functions used in the four steps of the MD5 algorithm
|
||||
and defined in the RFC 1321. The first function is a little bit optimized
|
||||
(as found in Colin Plumbs public domain implementation). */
|
||||
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
|
||||
#define FF(b, c, d) (d ^ (b & (c ^ d)))
|
||||
#define FG(b, c, d) FF (d, b, c)
|
||||
#define FH(b, c, d) (b ^ c ^ d)
|
||||
#define FI(b, c, d) (c ^ (b | ~d))
|
||||
|
||||
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
||||
It is assumed that LEN % 64 == 0. */
|
||||
static void
|
||||
md5_process_block (const void *buffer, size_t len, GstMD5Sink * ctx)
|
||||
{
|
||||
guint32 correct_words[16];
|
||||
const guint32 *words = buffer;
|
||||
size_t nwords = len / sizeof (guint32);
|
||||
const guint32 *endp = words + nwords;
|
||||
guint32 A = ctx->A;
|
||||
guint32 B = ctx->B;
|
||||
guint32 C = ctx->C;
|
||||
guint32 D = ctx->D;
|
||||
|
||||
/* First increment the byte count. RFC 1321 specifies the possible
|
||||
length of the file up to 2^64 bits. Here we only compute the
|
||||
number of bytes. Do a double word increment. */
|
||||
ctx->total[0] += len;
|
||||
if (ctx->total[0] < len)
|
||||
++ctx->total[1];
|
||||
|
||||
/* Process all bytes in the buffer with 64 bytes in each round of
|
||||
the loop. */
|
||||
while (words < endp) {
|
||||
guint32 *cwp = correct_words;
|
||||
guint32 A_save = A;
|
||||
guint32 B_save = B;
|
||||
guint32 C_save = C;
|
||||
guint32 D_save = D;
|
||||
|
||||
/* First round: using the given function, the context and a constant
|
||||
the next context is computed. Because the algorithms processing
|
||||
unit is a 32-bit word and it is determined to work on words in
|
||||
little endian byte order we perhaps have to change the byte order
|
||||
before the computation. To reduce the work for the next steps
|
||||
we store the swapped words in the array CORRECT_WORDS. */
|
||||
|
||||
#define OP(a, b, c, d, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += FF (b, c, d) + (*cwp++ = GUINT32_TO_LE (*words)) + T; \
|
||||
++words; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* It is unfortunate that C does not provide an operator for
|
||||
cyclic rotation. Hope the C compiler is smart enough. */
|
||||
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
|
||||
|
||||
/* Before we start, one word to the strange constants.
|
||||
They are defined in RFC 1321 as
|
||||
|
||||
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
|
||||
*/
|
||||
|
||||
/* Round 1. */
|
||||
OP (A, B, C, D, 7, 0xd76aa478);
|
||||
OP (D, A, B, C, 12, 0xe8c7b756);
|
||||
OP (C, D, A, B, 17, 0x242070db);
|
||||
OP (B, C, D, A, 22, 0xc1bdceee);
|
||||
OP (A, B, C, D, 7, 0xf57c0faf);
|
||||
OP (D, A, B, C, 12, 0x4787c62a);
|
||||
OP (C, D, A, B, 17, 0xa8304613);
|
||||
OP (B, C, D, A, 22, 0xfd469501);
|
||||
OP (A, B, C, D, 7, 0x698098d8);
|
||||
OP (D, A, B, C, 12, 0x8b44f7af);
|
||||
OP (C, D, A, B, 17, 0xffff5bb1);
|
||||
OP (B, C, D, A, 22, 0x895cd7be);
|
||||
OP (A, B, C, D, 7, 0x6b901122);
|
||||
OP (D, A, B, C, 12, 0xfd987193);
|
||||
OP (C, D, A, B, 17, 0xa679438e);
|
||||
OP (B, C, D, A, 22, 0x49b40821);
|
||||
|
||||
/* For the second to fourth round we have the possibly swapped words
|
||||
in CORRECT_WORDS. Redefine the macro to take an additional first
|
||||
argument specifying the function to use. */
|
||||
#undef OP
|
||||
#define OP(f, a, b, c, d, k, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += f (b, c, d) + correct_words[k] + T; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Round 2. */
|
||||
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
|
||||
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
|
||||
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
|
||||
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
|
||||
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
|
||||
OP (FG, D, A, B, C, 10, 9, 0x02441453);
|
||||
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
|
||||
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
|
||||
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
|
||||
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
|
||||
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
|
||||
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
|
||||
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
|
||||
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
|
||||
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
|
||||
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
|
||||
|
||||
/* Round 3. */
|
||||
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
|
||||
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
|
||||
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
|
||||
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
|
||||
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
|
||||
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
|
||||
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
|
||||
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
|
||||
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
|
||||
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
|
||||
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
|
||||
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
|
||||
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
|
||||
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
|
||||
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
|
||||
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
|
||||
|
||||
/* Round 4. */
|
||||
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
|
||||
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
|
||||
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
|
||||
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
|
||||
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
|
||||
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
|
||||
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
|
||||
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
|
||||
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
|
||||
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
|
||||
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
|
||||
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
|
||||
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
|
||||
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
|
||||
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
|
||||
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
|
||||
|
||||
/* Add the starting values of the context. */
|
||||
A += A_save;
|
||||
B += B_save;
|
||||
C += C_save;
|
||||
D += D_save;
|
||||
}
|
||||
|
||||
/* Put checksum in context given as argument. */
|
||||
ctx->A = A;
|
||||
ctx->B = B;
|
||||
ctx->C = C;
|
||||
ctx->D = D;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_md5sink_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
gst_element_class_set_details (gstelement_class, &gst_md5sink_details);
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&md5_sink_template));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_md5sink_class_init (GstMD5SinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_md5sink_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MD5,
|
||||
g_param_spec_string ("md5", "md5", "current value of the md5 sum",
|
||||
"", G_PARAM_READABLE));
|
||||
|
||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_md5sink_change_state);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_md5sink_init (GstMD5Sink * md5sink)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&md5_sink_template), "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (md5sink), pad);
|
||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_md5sink_chain));
|
||||
|
||||
md5_init_ctx (md5sink);
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_md5sink_change_state (GstElement * element)
|
||||
{
|
||||
GstMD5Sink *sink;
|
||||
|
||||
/* element check */
|
||||
sink = GST_MD5SINK (element);
|
||||
|
||||
g_return_val_if_fail (GST_IS_MD5SINK (sink), GST_STATE_FAILURE);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
md5_init_ctx (sink);
|
||||
g_object_notify (G_OBJECT (element), "md5");
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
md5_finish_ctx (sink, sink->md5);
|
||||
g_object_notify (G_OBJECT (element), "md5");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((GST_ELEMENT_CLASS (parent_class)->change_state))
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_md5sink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstMD5Sink *sink;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_MD5SINK (object));
|
||||
|
||||
sink = GST_MD5SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_MD5:
|
||||
{
|
||||
/* you could actually get a value for the current md5.
|
||||
* This is currently disabled.
|
||||
* md5_read_ctx (sink, sink->md5); */
|
||||
/* md5 is a guchar[16] */
|
||||
int i;
|
||||
gchar *md5string = g_malloc0 (33);
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
sprintf (md5string + i * 2, "%02x", sink->md5[i]);
|
||||
g_value_set_string (value, md5string);
|
||||
g_free (md5string);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_md5sink_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstMD5Sink *md5sink;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
md5sink = GST_MD5SINK (gst_pad_get_parent (pad));
|
||||
|
||||
if (GST_IS_BUFFER (buf)) {
|
||||
md5_process_bytes (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), md5sink);
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2002 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstmd5sink.h:
|
||||
*
|
||||
* 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_MD5SINK_H__
|
||||
#define __GST_MD5SINK_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_MD5SINK \
|
||||
(gst_md5sink_get_type())
|
||||
#define GST_MD5SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MD5SINK,GstMD5Sink))
|
||||
#define GST_MD5SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MD5SINK,GstMD5SinkClass))
|
||||
#define GST_IS_MD5SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MD5SINK))
|
||||
#define GST_IS_MD5SINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MD5SINK))
|
||||
|
||||
typedef struct _GstMD5Sink GstMD5Sink;
|
||||
typedef struct _GstMD5SinkClass GstMD5SinkClass;
|
||||
|
||||
struct _GstMD5Sink {
|
||||
GstElement element;
|
||||
|
||||
/* md5 information */
|
||||
guint32 A;
|
||||
guint32 B;
|
||||
guint32 C;
|
||||
guint32 D;
|
||||
|
||||
guint32 total[2];
|
||||
guint32 buflen;
|
||||
gchar buffer[128];
|
||||
|
||||
/* latest md5 */
|
||||
guchar md5[16];
|
||||
|
||||
};
|
||||
|
||||
struct _GstMD5SinkClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
GType gst_md5sink_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MD5SINK_H__ */
|
|
@ -1,366 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2001 Dominic Ludlam <dom@recoil.org>
|
||||
*
|
||||
* gstmultifilesrc.c:
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "../gst-i18n-lib.h"
|
||||
|
||||
#include "gstmultifilesrc.h"
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_multifilesrc_debug);
|
||||
#define GST_CAT_DEFAULT gst_multifilesrc_debug
|
||||
|
||||
GstElementDetails gst_multifilesrc_details =
|
||||
GST_ELEMENT_DETAILS ("Multi File Source",
|
||||
"Source/File",
|
||||
"Read from multiple files in order",
|
||||
"Dominic Ludlam <dom@openfx.org>");
|
||||
|
||||
/* FileSrc signals and args */
|
||||
enum
|
||||
{
|
||||
NEW_FILE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_LOCATIONS,
|
||||
ARG_HAVENEWMEDIA
|
||||
};
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_multifilesrc_debug, "multifilesrc", 0, "multifilesrc element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstMultiFileSrc, gst_multifilesrc, GstElement,
|
||||
GST_TYPE_ELEMENT, _do_init);
|
||||
|
||||
static void gst_multifilesrc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_multifilesrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstData *gst_multifilesrc_get (GstPad * pad);
|
||||
|
||||
/*static GstBuffer * gst_multifilesrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);*/
|
||||
|
||||
static GstElementStateReturn gst_multifilesrc_change_state (GstElement *
|
||||
element);
|
||||
|
||||
static gboolean gst_multifilesrc_open_file (GstMultiFileSrc * src,
|
||||
GstPad * srcpad);
|
||||
static void gst_multifilesrc_close_file (GstMultiFileSrc * src);
|
||||
|
||||
static guint gst_multifilesrc_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gst_multifilesrc_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 (gstelement_class, &gst_multifilesrc_details);
|
||||
}
|
||||
static void
|
||||
gst_multifilesrc_class_init (GstMultiFileSrcClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
|
||||
gst_multifilesrc_signals[NEW_FILE] =
|
||||
g_signal_new ("new-file", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstMultiFileSrcClass, new_file), NULL, NULL,
|
||||
g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
|
||||
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATIONS, g_param_spec_pointer ("locations", "locations", "locations", G_PARAM_READWRITE)); /* CHECKME */
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAVENEWMEDIA,
|
||||
g_param_spec_boolean ("newmedia", "newmedia",
|
||||
"generate new media events?", FALSE, G_PARAM_READWRITE));
|
||||
|
||||
|
||||
gobject_class->set_property = gst_multifilesrc_set_property;
|
||||
gobject_class->get_property = gst_multifilesrc_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_multifilesrc_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_multifilesrc_init (GstMultiFileSrc * multifilesrc)
|
||||
{
|
||||
/* GST_FLAG_SET (filesrc, GST_SRC_); */
|
||||
|
||||
multifilesrc->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_pad_set_get_function (multifilesrc->srcpad, gst_multifilesrc_get);
|
||||
/* gst_pad_set_getregion_function (multifilesrc->srcpad,gst_multifilesrc_get_region); */
|
||||
gst_element_add_pad (GST_ELEMENT (multifilesrc), multifilesrc->srcpad);
|
||||
|
||||
multifilesrc->listptr = NULL;
|
||||
multifilesrc->currentfilename = NULL;
|
||||
multifilesrc->fd = 0;
|
||||
multifilesrc->size = 0;
|
||||
multifilesrc->map = NULL;
|
||||
multifilesrc->new_seek = FALSE;
|
||||
multifilesrc->have_newmedia_events = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_multifilesrc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstMultiFileSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_MULTIFILESRC (object));
|
||||
|
||||
src = GST_MULTIFILESRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOCATIONS:
|
||||
/* the element must be stopped in order to do this */
|
||||
g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING);
|
||||
|
||||
/* clear the filename if we get a NULL */
|
||||
if (g_value_get_pointer (value) == NULL) {
|
||||
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
|
||||
src->listptr = NULL;
|
||||
/* otherwise set the new filenames */
|
||||
} else {
|
||||
src->listptr = g_value_get_pointer (value);
|
||||
}
|
||||
break;
|
||||
case ARG_HAVENEWMEDIA:
|
||||
src->have_newmedia_events = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_multifilesrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstMultiFileSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_MULTIFILESRC (object));
|
||||
|
||||
src = GST_MULTIFILESRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOCATIONS:
|
||||
g_value_set_pointer (value, src->listptr);
|
||||
break;
|
||||
case ARG_HAVENEWMEDIA:
|
||||
g_value_set_boolean (value, src->have_newmedia_events);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_filesrc_get:
|
||||
* @pad: #GstPad to push a buffer from
|
||||
*
|
||||
* Push a new buffer from the filesrc at the current offset.
|
||||
*/
|
||||
static GstData *
|
||||
gst_multifilesrc_get (GstPad * pad)
|
||||
{
|
||||
GstMultiFileSrc *src;
|
||||
GstBuffer *buf;
|
||||
GstEvent *newmedia;
|
||||
GSList *list;
|
||||
|
||||
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
src = GST_MULTIFILESRC (gst_pad_get_parent (pad));
|
||||
|
||||
GST_DEBUG ("curfileindex = %d newmedia flag = %s", src->curfileindex,
|
||||
GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE) ? "true" : "false");
|
||||
|
||||
switch (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE)) {
|
||||
case FALSE:
|
||||
if (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN))
|
||||
gst_multifilesrc_close_file (src);
|
||||
|
||||
if (!src->listptr) {
|
||||
GST_DEBUG ("sending EOS event");
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
}
|
||||
|
||||
list = src->listptr;
|
||||
src->currentfilename = (gchar *) list->data;
|
||||
src->listptr = src->listptr->next;
|
||||
|
||||
if (!gst_multifilesrc_open_file (src, pad))
|
||||
return NULL;
|
||||
src->curfileindex++;
|
||||
/* emitted after the open, as the user may free the list and string from here */
|
||||
g_signal_emit (G_OBJECT (src), gst_multifilesrc_signals[NEW_FILE], 0,
|
||||
list);
|
||||
if (src->have_newmedia_events) {
|
||||
newmedia =
|
||||
gst_event_new_discontinuous (TRUE, GST_FORMAT_TIME, (gint64) 0,
|
||||
GST_FORMAT_UNDEFINED);
|
||||
GST_FLAG_SET (src, GST_MULTIFILESRC_NEWFILE);
|
||||
|
||||
GST_DEBUG ("sending new media event");
|
||||
return GST_DATA (newmedia);
|
||||
}
|
||||
default:
|
||||
if (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_NEWFILE))
|
||||
GST_FLAG_UNSET (src, GST_MULTIFILESRC_NEWFILE);
|
||||
/* create the buffer */
|
||||
/* FIXME: should eventually use a bufferpool for this */
|
||||
buf = gst_buffer_new ();
|
||||
|
||||
g_return_val_if_fail (buf != NULL, NULL);
|
||||
|
||||
/* simply set the buffer to point to the correct region of the file */
|
||||
GST_BUFFER_DATA (buf) = src->map;
|
||||
GST_BUFFER_SIZE (buf) = src->size;
|
||||
GST_BUFFER_OFFSET (buf) = 0;
|
||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
|
||||
|
||||
if (src->new_seek) {
|
||||
/* fixme, do something here */
|
||||
src->new_seek = FALSE;
|
||||
}
|
||||
|
||||
/* we're done, return the buffer */
|
||||
GST_DEBUG ("sending buffer");
|
||||
return GST_DATA (buf);
|
||||
}
|
||||
|
||||
/* should not reach here */
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open the file and mmap it, necessary to go to READY state */
|
||||
static gboolean
|
||||
gst_multifilesrc_open_file (GstMultiFileSrc * src, GstPad * srcpad)
|
||||
{
|
||||
g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN), FALSE);
|
||||
|
||||
if (src->currentfilename == NULL || src->currentfilename[0] == '\0') {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
|
||||
(_("No file name specified for reading.")), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* open the file. FIXME: do we need to use O_LARGEFILE here? */
|
||||
src->fd = open ((const char *) src->currentfilename, O_RDONLY);
|
||||
if (src->fd < 0) {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
|
||||
(_("Could not open file \"%s\" for reading."), src->currentfilename),
|
||||
GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
|
||||
} else {
|
||||
/* find the file length */
|
||||
src->size = lseek (src->fd, 0, SEEK_END);
|
||||
lseek (src->fd, 0, SEEK_SET);
|
||||
/* map the file into memory.
|
||||
* FIXME: don't map the whole file at once, there might
|
||||
* be restrictions set. Get max size via getrlimit
|
||||
* or re-try with smaller size if mmap fails with ENOMEM? */
|
||||
src->map = mmap (NULL, src->size, PROT_READ, MAP_SHARED, src->fd, 0);
|
||||
madvise (src->map, src->size, MADV_SEQUENTIAL);
|
||||
/* collapse state if that failed */
|
||||
if (src->map == NULL) {
|
||||
close (src->fd);
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL),
|
||||
("mmap call failed."));
|
||||
return FALSE;
|
||||
}
|
||||
GST_FLAG_SET (src, GST_MULTIFILESRC_OPEN);
|
||||
src->new_seek = TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* unmap and close the file */
|
||||
static void
|
||||
gst_multifilesrc_close_file (GstMultiFileSrc * src)
|
||||
{
|
||||
g_return_if_fail (GST_FLAG_IS_SET (src, GST_MULTIFILESRC_OPEN));
|
||||
|
||||
/* unmap the file from memory and close the file */
|
||||
munmap (src->map, src->size);
|
||||
close (src->fd);
|
||||
|
||||
/* zero out a lot of our state */
|
||||
src->fd = 0;
|
||||
src->size = 0;
|
||||
src->map = NULL;
|
||||
src->new_seek = FALSE;
|
||||
|
||||
GST_FLAG_UNSET (src, GST_MULTIFILESRC_OPEN);
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_multifilesrc_change_state (GstElement * element)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_MULTIFILESRC (element), GST_STATE_FAILURE);
|
||||
|
||||
if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
|
||||
if (GST_FLAG_IS_SET (element, GST_MULTIFILESRC_OPEN))
|
||||
gst_multifilesrc_close_file (GST_MULTIFILESRC (element));
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2001 Dominic Ludlam <dom@recoil.org>
|
||||
*
|
||||
* gstmultifilesrc.h:
|
||||
*
|
||||
* 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_MULTIFILESRC_H__
|
||||
#define __GST_MULTIFILESRC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_MULTIFILESRC \
|
||||
(gst_multifilesrc_get_type())
|
||||
#define GST_MULTIFILESRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTIFILESRC,GstMultiFileSrc))
|
||||
#define GST_MULTIFILESRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTIFILESRC,GstMultiFileSrcClass))
|
||||
#define GST_IS_MULTIFILESRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTIFILESRC))
|
||||
#define GST_IS_MULTIFILESRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTIFILESRC))
|
||||
|
||||
typedef enum {
|
||||
GST_MULTIFILESRC_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
GST_MULTIFILESRC_NEWFILE = GST_ELEMENT_FLAG_LAST + 2,
|
||||
|
||||
GST_MULTIFILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4
|
||||
} GstMultiFileSrcFlags;
|
||||
|
||||
typedef struct _GstMultiFileSrc GstMultiFileSrc;
|
||||
typedef struct _GstMultiFileSrcClass GstMultiFileSrcClass;
|
||||
|
||||
struct _GstMultiFileSrc {
|
||||
GstElement element;
|
||||
/* pads */
|
||||
GstPad *srcpad;
|
||||
|
||||
/* current file details */
|
||||
gchar *currentfilename;
|
||||
GSList *listptr;
|
||||
|
||||
/* mapping parameters */
|
||||
gint fd;
|
||||
gulong size; /* how long is the file? */
|
||||
guchar *map; /* where the file is mapped to */
|
||||
|
||||
gint curfileindex; /* how many files have we done so far */
|
||||
|
||||
gboolean have_newmedia_events; /* tunable parameter to say whether new media
|
||||
disconts should be generated */
|
||||
|
||||
gboolean new_seek;
|
||||
};
|
||||
|
||||
struct _GstMultiFileSrcClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
void (*new_file) (GstMultiFileSrc *multifilesrc, gchar *newfilename);
|
||||
};
|
||||
|
||||
GType gst_multifilesrc_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MULTIFILESRC_H__ */
|
|
@ -1,371 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstpipefilter.c:
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#include <process.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "../gst-i18n-lib.h"
|
||||
#include "gstpipefilter.h"
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_pipefilter_debug);
|
||||
#define GST_CAT_DEFAULT gst_pipefilter_debug
|
||||
|
||||
GstElementDetails gst_pipefilter_details = GST_ELEMENT_DETAILS ("Pipefilter",
|
||||
"Filter",
|
||||
"Interoperate with an external program using stdin and stdout",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim.taymans@chello.be>");
|
||||
|
||||
|
||||
/* Pipefilter signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_COMMAND
|
||||
};
|
||||
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstPipefilter, gst_pipefilter, GstElement,
|
||||
GST_TYPE_ELEMENT, _do_init);
|
||||
|
||||
static void gst_pipefilter_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_pipefilter_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstData *gst_pipefilter_get (GstPad * pad);
|
||||
static void gst_pipefilter_chain (GstPad * pad, GstData * _data);
|
||||
static gboolean gst_pipefilter_handle_event (GstPad * pad, GstEvent * event);
|
||||
|
||||
static GstElementStateReturn gst_pipefilter_change_state (GstElement * element);
|
||||
|
||||
static void
|
||||
gst_pipefilter_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 (gstelement_class, &gst_pipefilter_details);
|
||||
}
|
||||
static void
|
||||
gst_pipefilter_class_init (GstPipefilterClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
|
||||
gobject_class->set_property = gst_pipefilter_set_property;
|
||||
gobject_class->get_property = gst_pipefilter_get_property;
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMMAND, g_param_spec_string ("command", "command", "command", NULL, G_PARAM_READWRITE)); /* CHECKME */
|
||||
|
||||
gstelement_class->change_state = gst_pipefilter_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pipefilter_init (GstPipefilter * pipefilter)
|
||||
{
|
||||
GST_FLAG_SET (pipefilter, GST_ELEMENT_DECOUPLED);
|
||||
|
||||
pipefilter->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (pipefilter), pipefilter->sinkpad);
|
||||
gst_pad_set_chain_function (pipefilter->sinkpad, gst_pipefilter_chain);
|
||||
|
||||
pipefilter->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_element_add_pad (GST_ELEMENT (pipefilter), pipefilter->srcpad);
|
||||
gst_pad_set_get_function (pipefilter->srcpad, gst_pipefilter_get);
|
||||
|
||||
pipefilter->command = NULL;
|
||||
pipefilter->curoffset = 0;
|
||||
pipefilter->bytes_per_read = 4096;
|
||||
pipefilter->seq = 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_pipefilter_handle_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstPipefilter *pipefilter;
|
||||
|
||||
pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
|
||||
|
||||
GST_DEBUG ("pipefilter: %s received event", GST_ELEMENT_NAME (pipefilter));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
if (close (pipefilter->fdin[1]) < 0)
|
||||
perror ("close");
|
||||
if (close (pipefilter->fdout[0]) < 0)
|
||||
perror ("close");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gst_pad_event_default (pad, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstData *
|
||||
gst_pipefilter_get (GstPad * pad)
|
||||
{
|
||||
GstPipefilter *pipefilter;
|
||||
GstBuffer *newbuf;
|
||||
glong readbytes;
|
||||
|
||||
pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
|
||||
|
||||
/* create the buffer */
|
||||
/* FIXME: should eventually use a bufferpool for this */
|
||||
newbuf = gst_buffer_new ();
|
||||
g_return_val_if_fail (newbuf, NULL);
|
||||
|
||||
/* allocate the space for the buffer data */
|
||||
GST_BUFFER_DATA (newbuf) = g_malloc (pipefilter->bytes_per_read);
|
||||
g_return_val_if_fail (GST_BUFFER_DATA (newbuf) != NULL, NULL);
|
||||
|
||||
/* read it in from the file */
|
||||
GST_DEBUG ("attemting to read %ld bytes", pipefilter->bytes_per_read);
|
||||
readbytes =
|
||||
read (pipefilter->fdout[0], GST_BUFFER_DATA (newbuf),
|
||||
pipefilter->bytes_per_read);
|
||||
GST_DEBUG ("read %ld bytes", readbytes);
|
||||
if (readbytes < 0) {
|
||||
GST_ELEMENT_ERROR (pipefilter, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
|
||||
return NULL;
|
||||
}
|
||||
/* if we didn't get as many bytes as we asked for, we're at EOF */
|
||||
if (readbytes == 0) {
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
|
||||
}
|
||||
|
||||
GST_BUFFER_OFFSET (newbuf) = pipefilter->curoffset;
|
||||
GST_BUFFER_SIZE (newbuf) = readbytes;
|
||||
pipefilter->curoffset += readbytes;
|
||||
|
||||
return GST_DATA (newbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pipefilter_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
GstPipefilter *pipefilter;
|
||||
glong writebytes;
|
||||
guchar *data;
|
||||
gulong size;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
|
||||
if (GST_IS_EVENT (_data)) {
|
||||
gst_pipefilter_handle_event (pad, GST_EVENT (_data));
|
||||
return;
|
||||
}
|
||||
|
||||
pipefilter = GST_PIPEFILTER (gst_pad_get_parent (pad));
|
||||
|
||||
buf = GST_BUFFER (_data);
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
size = GST_BUFFER_SIZE (buf);
|
||||
|
||||
GST_DEBUG ("attemting to write %ld bytes", size);
|
||||
writebytes = write (pipefilter->fdin[1], data, size);
|
||||
GST_DEBUG ("written %ld bytes", writebytes);
|
||||
if (writebytes < 0) {
|
||||
GST_ELEMENT_ERROR (pipefilter, RESOURCE, WRITE, (NULL), GST_ERROR_SYSTEM);
|
||||
return;
|
||||
}
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pipefilter_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstPipefilter *pipefilter;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_PIPEFILTER (object));
|
||||
pipefilter = GST_PIPEFILTER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_COMMAND:
|
||||
pipefilter->orig_command = g_strdup (g_value_get_string (value));
|
||||
pipefilter->command = g_strsplit (g_value_get_string (value), " ", 0);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pipefilter_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstPipefilter *pipefilter;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_PIPEFILTER (object));
|
||||
pipefilter = GST_PIPEFILTER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_COMMAND:
|
||||
g_value_set_string (value, pipefilter->orig_command);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* open the file, necessary to go to RUNNING state */
|
||||
static gboolean
|
||||
gst_pipefilter_open_file (GstPipefilter * src)
|
||||
{
|
||||
g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_PIPEFILTER_OPEN), FALSE);
|
||||
|
||||
pipe (src->fdin);
|
||||
pipe (src->fdout);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
src->childpid = 0;
|
||||
#else
|
||||
if ((src->childpid = fork ()) == -1) {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (src->childpid == 0) {
|
||||
close (src->fdin[1]);
|
||||
close (src->fdout[0]);
|
||||
/* child */
|
||||
#ifdef _MSC_VER
|
||||
dup2 (src->fdin[0], fileno (stdin)); /* set the childs input stream */
|
||||
dup2 (src->fdout[1], fileno (stdout)); /* set the childs output stream */
|
||||
#else
|
||||
dup2 (src->fdin[0], STDIN_FILENO); /* set the childs input stream */
|
||||
dup2 (src->fdout[1], STDOUT_FILENO); /* set the childs output stream */
|
||||
#endif
|
||||
execvp (src->command[0], &src->command[0]);
|
||||
/* will only be reached if execvp has an error */
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
|
||||
} else {
|
||||
close (src->fdin[0]);
|
||||
close (src->fdout[1]);
|
||||
}
|
||||
|
||||
GST_FLAG_SET (src, GST_PIPEFILTER_OPEN);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* close the file */
|
||||
static void
|
||||
gst_pipefilter_close_file (GstPipefilter * src)
|
||||
{
|
||||
g_return_if_fail (GST_FLAG_IS_SET (src, GST_PIPEFILTER_OPEN));
|
||||
|
||||
/* close the file */
|
||||
close (src->fdout[0]);
|
||||
close (src->fdout[1]);
|
||||
close (src->fdin[0]);
|
||||
close (src->fdin[1]);
|
||||
|
||||
/* zero out a lot of our state */
|
||||
src->curoffset = 0;
|
||||
src->seq = 0;
|
||||
|
||||
GST_FLAG_UNSET (src, GST_PIPEFILTER_OPEN);
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_pipefilter_change_state (GstElement * element)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_PIPEFILTER (element), FALSE);
|
||||
|
||||
/* if going down into NULL state, close the file if it's open */
|
||||
if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
|
||||
if (GST_FLAG_IS_SET (element, GST_PIPEFILTER_OPEN))
|
||||
gst_pipefilter_close_file (GST_PIPEFILTER (element));
|
||||
/* otherwise (READY or higher) we need to open the file */
|
||||
} else {
|
||||
if (!GST_FLAG_IS_SET (element, GST_PIPEFILTER_OPEN)) {
|
||||
if (!gst_pipefilter_open_file (GST_PIPEFILTER (element)))
|
||||
return GST_STATE_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstpipefilter.h:
|
||||
*
|
||||
* 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_PIPEFILTER_H__
|
||||
#define __GST_PIPEFILTER_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_PIPEFILTER \
|
||||
(gst_pipefilter_get_type())
|
||||
#define GST_PIPEFILTER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PIPEFILTER,GstPipefilter))
|
||||
#define GST_PIPEFILTER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PIPEFILTER,GstPipefilterClass))
|
||||
#define GST_IS_PIPEFILTER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PIPEFILTER))
|
||||
#define GST_IS_PIPEFILTER_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PIPEFILTER))
|
||||
|
||||
typedef enum {
|
||||
GST_PIPEFILTER_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_PIPEFILTER_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
|
||||
} GstPipeFilterFlags;
|
||||
|
||||
typedef struct _GstPipefilter GstPipefilter;
|
||||
typedef struct _GstPipefilterClass GstPipefilterClass;
|
||||
|
||||
struct _GstPipefilter {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
/* command */
|
||||
gchar **command;
|
||||
gchar *orig_command;
|
||||
/* fd */
|
||||
gint fdout[2];
|
||||
gint fdin[2];
|
||||
#ifdef _MSC_VER
|
||||
int childpid;
|
||||
#else
|
||||
pid_t childpid;
|
||||
#endif
|
||||
|
||||
gulong curoffset; /* current offset in file */
|
||||
gulong bytes_per_read; /* bytes per read */
|
||||
|
||||
gulong seq; /* buffer sequence number */
|
||||
};
|
||||
|
||||
struct _GstPipefilterClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_pipefilter_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_PIPEFILTER_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,119 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstqueue.h:
|
||||
*
|
||||
* 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_QUEUE_H__
|
||||
#define __GST_QUEUE_H__
|
||||
|
||||
|
||||
#include <gst/gstelement.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_QUEUE \
|
||||
(gst_queue_get_type())
|
||||
#define GST_QUEUE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QUEUE,GstQueue))
|
||||
#define GST_QUEUE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QUEUE,GstQueueClass))
|
||||
#define GST_IS_QUEUE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QUEUE))
|
||||
#define GST_IS_QUEUE_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
|
||||
|
||||
enum {
|
||||
GST_QUEUE_NO_LEAK = 0,
|
||||
GST_QUEUE_LEAK_UPSTREAM = 1,
|
||||
GST_QUEUE_LEAK_DOWNSTREAM = 2
|
||||
};
|
||||
|
||||
typedef struct _GstQueue GstQueue;
|
||||
typedef struct _GstQueueSize GstQueueSize;
|
||||
typedef struct _GstQueueClass GstQueueClass;
|
||||
|
||||
struct _GstQueueSize {
|
||||
guint buffers; /* no. of buffers */
|
||||
guint bytes; /* no. of bytes */
|
||||
guint64 time; /* amount of time */
|
||||
};
|
||||
|
||||
struct _GstQueue {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
/* the queue of data we're keeping our grubby hands on */
|
||||
GQueue *queue;
|
||||
|
||||
GstQueueSize
|
||||
cur_level, /* currently in the queue */
|
||||
max_size, /* max. amount of data allowed in the queue */
|
||||
min_threshold; /* min. amount of data required to wake reader */
|
||||
|
||||
/* whether we leak data, and at which end */
|
||||
gint leaky;
|
||||
|
||||
/* number of nanoseconds until a blocked queue 'times out'
|
||||
* to receive data and returns a filler event. -1 = disable */
|
||||
guint64 block_timeout;
|
||||
|
||||
/* it the queue should fail on possible deadlocks */
|
||||
gboolean may_deadlock;
|
||||
|
||||
gboolean interrupt;
|
||||
gboolean flush;
|
||||
|
||||
GMutex *qlock; /* lock for queue (vs object lock) */
|
||||
GCond *item_add; /* signals buffers now available for reading */
|
||||
GCond *item_del; /* signals space now available for writing */
|
||||
GCond *event_done; /* upstream event signaller */
|
||||
|
||||
GTimeVal *timeval; /* the timeout for the queue locking */
|
||||
GQueue *events; /* upstream events get decoupled here */
|
||||
|
||||
GstCaps *negotiated_caps;
|
||||
|
||||
GMutex *event_lock; /* lock when handling the events queue */
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING - 1];
|
||||
};
|
||||
|
||||
struct _GstQueueClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals - 'running' is called from both sides
|
||||
* which might make it sort of non-useful... */
|
||||
void (*underrun) (GstQueue *queue);
|
||||
void (*running) (GstQueue *queue);
|
||||
void (*overrun) (GstQueue *queue);
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
GType gst_queue_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __GST_QUEUE_H__ */
|
|
@ -1,374 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstshaper.c:
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstshaper.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_shaper_debug);
|
||||
#define GST_CAT_DEFAULT gst_shaper_debug
|
||||
|
||||
GstElementDetails gst_shaper_details = GST_ELEMENT_DETAILS ("Shaper",
|
||||
"Generic",
|
||||
"Synchronizes streams on different pads",
|
||||
"Wim Taymans <wim.taymans@chello.be>");
|
||||
|
||||
|
||||
/* Shaper signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_POLICY,
|
||||
ARG_SILENT,
|
||||
ARG_LAST_MESSAGE
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
GstBuffer *buffer;
|
||||
}
|
||||
GstShaperConnection;
|
||||
|
||||
GstStaticPadTemplate shaper_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_SOMETIMES,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GstStaticPadTemplate shaper_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define GST_TYPE_SHAPER_POLICY (gst_shaper_policy_get_type())
|
||||
static GType
|
||||
gst_shaper_policy_get_type (void)
|
||||
{
|
||||
static GType shaper_policy_type = 0;
|
||||
static GEnumValue shaper_policy[] = {
|
||||
{SHAPER_POLICY_TIMESTAMPS, "1", "sync on timestamps"},
|
||||
{SHAPER_POLICY_BUFFERSIZE, "2", "sync on buffer size"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!shaper_policy_type) {
|
||||
shaper_policy_type =
|
||||
g_enum_register_static ("GstShaperPolicy", shaper_policy);
|
||||
}
|
||||
return shaper_policy_type;
|
||||
}
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstShaper, gst_shaper, GstElement, GST_TYPE_ELEMENT,
|
||||
_do_init);
|
||||
|
||||
static void gst_shaper_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_shaper_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstPad *gst_shaper_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * unused);
|
||||
|
||||
static void gst_shaper_loop (GstElement * element);
|
||||
|
||||
|
||||
static void
|
||||
gst_shaper_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
gst_element_class_set_details (gstelement_class, &gst_shaper_details);
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&shaper_src_template));
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&shaper_sink_template));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_shaper_class_init (GstShaperClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POLICY,
|
||||
g_param_spec_enum ("policy", "Policy", "Shaper policy",
|
||||
GST_TYPE_SHAPER_POLICY, SHAPER_POLICY_TIMESTAMPS, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last-message", "last-message", "last-message",
|
||||
NULL, G_PARAM_READABLE));
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_shaper_request_new_pad);
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_shaper_getcaps (GstPad * pad)
|
||||
{
|
||||
GstPad *otherpad;
|
||||
GstShaperConnection *connection;
|
||||
|
||||
connection = gst_pad_get_element_private (pad);
|
||||
|
||||
otherpad =
|
||||
(pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
|
||||
|
||||
if (GST_PAD_PEER (otherpad)) {
|
||||
return gst_pad_get_caps (GST_PAD_PEER (otherpad));
|
||||
} else {
|
||||
return gst_caps_new_any ();
|
||||
}
|
||||
}
|
||||
|
||||
static GList *
|
||||
gst_shaper_get_internal_link (GstPad * pad)
|
||||
{
|
||||
GList *res = NULL;
|
||||
GstShaperConnection *connection;
|
||||
GstPad *otherpad;
|
||||
|
||||
connection = gst_pad_get_element_private (pad);
|
||||
|
||||
otherpad =
|
||||
(pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
|
||||
|
||||
res = g_list_prepend (res, otherpad);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_shaper_link (GstPad * pad, const GstCaps * caps)
|
||||
{
|
||||
GstPad *otherpad;
|
||||
GstShaperConnection *connection;
|
||||
|
||||
connection = gst_pad_get_element_private (pad);
|
||||
|
||||
otherpad =
|
||||
(pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
|
||||
|
||||
return gst_pad_try_set_caps (otherpad, caps);
|
||||
}
|
||||
|
||||
static GstShaperConnection *
|
||||
gst_shaper_create_connection (GstShaper * shaper)
|
||||
{
|
||||
GstShaperConnection *connection;
|
||||
gchar *padname;
|
||||
|
||||
shaper->nconnections++;
|
||||
|
||||
connection = g_new0 (GstShaperConnection, 1);
|
||||
|
||||
padname = g_strdup_printf ("sink%d", shaper->nconnections);
|
||||
connection->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&shaper_sink_template), padname);
|
||||
g_free (padname);
|
||||
gst_pad_set_getcaps_function (connection->sinkpad, gst_shaper_getcaps);
|
||||
gst_pad_set_internal_link_function (connection->sinkpad,
|
||||
gst_shaper_get_internal_link);
|
||||
gst_pad_set_link_function (connection->sinkpad, gst_shaper_link);
|
||||
gst_pad_set_element_private (connection->sinkpad, connection);
|
||||
gst_element_add_pad (GST_ELEMENT (shaper), connection->sinkpad);
|
||||
|
||||
padname = g_strdup_printf ("src%d", shaper->nconnections);
|
||||
connection->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&shaper_src_template), padname);
|
||||
g_free (padname);
|
||||
gst_pad_set_getcaps_function (connection->srcpad, gst_shaper_getcaps);
|
||||
gst_pad_set_internal_link_function (connection->srcpad,
|
||||
gst_shaper_get_internal_link);
|
||||
gst_pad_set_link_function (connection->srcpad, gst_shaper_link);
|
||||
gst_pad_set_element_private (connection->srcpad, connection);
|
||||
gst_element_add_pad (GST_ELEMENT (shaper), connection->srcpad);
|
||||
|
||||
shaper->connections = g_slist_prepend (shaper->connections, connection);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_shaper_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
GstShaper *shaper = GST_SHAPER (element);
|
||||
GstShaperConnection *connection;
|
||||
|
||||
connection = gst_shaper_create_connection (shaper);
|
||||
|
||||
return connection->sinkpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_shaper_init (GstShaper * shaper)
|
||||
{
|
||||
gst_element_set_loop_function (GST_ELEMENT (shaper), gst_shaper_loop);
|
||||
|
||||
shaper->policy = SHAPER_POLICY_TIMESTAMPS;
|
||||
shaper->connections = NULL;
|
||||
shaper->nconnections = 0;
|
||||
shaper->silent = FALSE;
|
||||
shaper->last_message = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_shaper_loop (GstElement * element)
|
||||
{
|
||||
GstShaper *shaper;
|
||||
GSList *connections;
|
||||
gboolean eos = TRUE;
|
||||
GstShaperConnection *min = NULL;
|
||||
|
||||
shaper = GST_SHAPER (element);
|
||||
|
||||
/* first make sure we have a buffer on all pads */
|
||||
connections = shaper->connections;
|
||||
while (connections) {
|
||||
GstShaperConnection *connection = (GstShaperConnection *) connections->data;
|
||||
|
||||
/* try to fill a connection without a buffer on a pad that is
|
||||
* active */
|
||||
if (connection->buffer == NULL && GST_PAD_IS_USABLE (connection->sinkpad)) {
|
||||
GstBuffer *buffer;
|
||||
|
||||
buffer = GST_BUFFER (gst_pad_pull (connection->sinkpad));
|
||||
|
||||
/* events are simply pushed ASAP */
|
||||
if (GST_IS_EVENT (buffer)) {
|
||||
/* save event type as it will be unreffed after the next push */
|
||||
GstEventType type = GST_EVENT_TYPE (buffer);
|
||||
|
||||
gst_pad_push (connection->srcpad, GST_DATA (buffer));
|
||||
|
||||
switch (type) {
|
||||
/* on EOS we disable the pad so that we don't pull on
|
||||
* it again and never get more data */
|
||||
case GST_EVENT_EOS:
|
||||
gst_pad_set_active (connection->sinkpad, FALSE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* we store the buffer */
|
||||
connection->buffer = buffer;
|
||||
}
|
||||
}
|
||||
/* FIXME policy stuff goes here */
|
||||
/* find connection with lowest timestamp */
|
||||
if (min == NULL || (connection->buffer != NULL &&
|
||||
(GST_BUFFER_TIMESTAMP (connection->buffer) <
|
||||
GST_BUFFER_TIMESTAMP (min->buffer)))) {
|
||||
min = connection;
|
||||
}
|
||||
connections = g_slist_next (connections);
|
||||
}
|
||||
/* if we have a connection with a buffer, push it */
|
||||
if (min != NULL && min->buffer) {
|
||||
gst_pad_push (min->srcpad, GST_DATA (min->buffer));
|
||||
min->buffer = NULL;
|
||||
/* since we pushed a buffer, it's not EOS */
|
||||
eos = FALSE;
|
||||
}
|
||||
|
||||
if (eos) {
|
||||
gst_element_set_eos (element);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_shaper_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstShaper *shaper;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_SHAPER (object));
|
||||
|
||||
shaper = GST_SHAPER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_POLICY:
|
||||
shaper->policy = g_value_get_enum (value);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
shaper->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_shaper_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstShaper *shaper;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_SHAPER (object));
|
||||
|
||||
shaper = GST_SHAPER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_POLICY:
|
||||
g_value_set_enum (value, shaper->policy);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, shaper->silent);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
g_value_set_string (value, shaper->last_message);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gstshaper.h:
|
||||
*
|
||||
* 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_SHAPER_H__
|
||||
#define __GST_SHAPER_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_SHAPER \
|
||||
(gst_shaper_get_type())
|
||||
#define GST_SHAPER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHAPER,GstShaper))
|
||||
#define GST_SHAPER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHAPER,GstShaperClass))
|
||||
#define GST_IS_SHAPER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHAPER))
|
||||
#define GST_IS_SHAPER_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHAPER))
|
||||
|
||||
typedef enum {
|
||||
SHAPER_POLICY_TIMESTAMPS = 1,
|
||||
SHAPER_POLICY_BUFFERSIZE
|
||||
} GstShaperPolicyType;
|
||||
|
||||
typedef struct _GstShaper GstShaper;
|
||||
typedef struct _GstShaperClass GstShaperClass;
|
||||
|
||||
struct _GstShaper {
|
||||
GstElement element;
|
||||
|
||||
GSList *connections;
|
||||
gint nconnections;
|
||||
|
||||
GstShaperPolicyType policy;
|
||||
|
||||
gboolean silent;
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstShaperClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_shaper_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_SHAPER_H__ */
|
|
@ -1,416 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gststatistics.c:
|
||||
*
|
||||
* 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 "gststatistics.h"
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_statistics_debug);
|
||||
#define GST_CAT_DEFAULT gst_statistics_debug
|
||||
|
||||
GstElementDetails gst_statistics_details = GST_ELEMENT_DETAILS ("Statistics",
|
||||
"Generic",
|
||||
"Statistics on buffers/bytes/events",
|
||||
"David I. Lehn <dlehn@users.sourceforge.net>");
|
||||
|
||||
|
||||
/* Statistics signals and args */
|
||||
enum
|
||||
{
|
||||
SIGNAL_UPDATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_BUFFERS,
|
||||
ARG_BYTES,
|
||||
ARG_EVENTS,
|
||||
ARG_BUFFER_UPDATE_FREQ,
|
||||
ARG_BYTES_UPDATE_FREQ,
|
||||
ARG_EVENT_UPDATE_FREQ,
|
||||
ARG_UPDATE_ON_EOS,
|
||||
ARG_UPDATE,
|
||||
ARG_SILENT
|
||||
};
|
||||
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstStatistics, gst_statistics, GstElement,
|
||||
GST_TYPE_ELEMENT, _do_init);
|
||||
|
||||
static void gst_statistics_finalize (GObject * object);
|
||||
static void gst_statistics_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_statistics_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_statistics_chain (GstPad * pad, GstData * _data);
|
||||
static void gst_statistics_reset (GstStatistics * statistics);
|
||||
static void gst_statistics_print (GstStatistics * statistics);
|
||||
|
||||
static guint gst_statistics_signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
static stats zero_stats = { 0, };
|
||||
|
||||
|
||||
static void
|
||||
gst_statistics_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 (gstelement_class, &gst_statistics_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_finalize (GObject * object)
|
||||
{
|
||||
GstStatistics *statistics;
|
||||
|
||||
statistics = GST_STATISTICS (object);
|
||||
|
||||
if (statistics->timer)
|
||||
g_timer_destroy (statistics->timer);
|
||||
|
||||
if (statistics->last_timer)
|
||||
g_timer_destroy (statistics->last_timer);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_class_init (GstStatisticsClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFERS,
|
||||
g_param_spec_int64 ("buffers", "buffers", "total buffers count",
|
||||
0, G_MAXINT64, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTES,
|
||||
g_param_spec_int64 ("bytes", "bytes", "total bytes count",
|
||||
0, G_MAXINT64, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENTS,
|
||||
g_param_spec_int64 ("events", "events", "total event count",
|
||||
0, G_MAXINT64, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
ARG_BUFFER_UPDATE_FREQ, g_param_spec_int64 ("buffer_update_freq",
|
||||
"buffer update freq", "buffer update frequency", 0, G_MAXINT64, 0,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
ARG_BYTES_UPDATE_FREQ, g_param_spec_int64 ("bytes_update_freq",
|
||||
"bytes update freq", "bytes update frequency", 0, G_MAXINT64, 0,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
ARG_EVENT_UPDATE_FREQ, g_param_spec_int64 ("event_update_freq",
|
||||
"event update freq", "event update frequency", 0, G_MAXINT64, 0,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE_ON_EOS,
|
||||
g_param_spec_boolean ("update_on_eos", "update on EOS",
|
||||
"update on EOS event", TRUE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE,
|
||||
g_param_spec_boolean ("update", "update", "update", TRUE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent", TRUE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
gst_statistics_signals[SIGNAL_UPDATE] =
|
||||
g_signal_new ("update", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstStatisticsClass, update), NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||
|
||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_statistics_finalize);
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_statistics_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_statistics_get_property);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_init (GstStatistics * statistics)
|
||||
{
|
||||
statistics->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (statistics), statistics->sinkpad);
|
||||
gst_pad_set_chain_function (statistics->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_statistics_chain));
|
||||
|
||||
statistics->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_element_add_pad (GST_ELEMENT (statistics), statistics->srcpad);
|
||||
|
||||
statistics->timer = NULL;
|
||||
statistics->last_timer = NULL;
|
||||
gst_statistics_reset (statistics);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_reset (GstStatistics * statistics)
|
||||
{
|
||||
g_return_if_fail (statistics != NULL);
|
||||
g_return_if_fail (GST_IS_STATISTICS (statistics));
|
||||
|
||||
statistics->stats.buffers = 0;
|
||||
statistics->stats.bytes = 0;
|
||||
statistics->stats.events = 0;
|
||||
|
||||
statistics->last_stats.buffers = 0;
|
||||
statistics->last_stats.bytes = 0;
|
||||
statistics->last_stats.events = 0;
|
||||
|
||||
statistics->update_count.buffers = 0;
|
||||
statistics->update_count.bytes = 0;
|
||||
statistics->update_count.events = 0;
|
||||
|
||||
statistics->update_freq.buffers = 0;
|
||||
statistics->update_freq.bytes = 0;
|
||||
statistics->update_freq.events = 0;
|
||||
|
||||
statistics->update_on_eos = TRUE;
|
||||
statistics->update = TRUE;
|
||||
statistics->silent = FALSE;
|
||||
|
||||
if (!statistics->timer) {
|
||||
statistics->timer = g_timer_new ();
|
||||
}
|
||||
if (!statistics->last_timer) {
|
||||
statistics->last_timer = g_timer_new ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_stats (gboolean first, const gchar * name, const gchar * type,
|
||||
stats * base, stats * final, double time)
|
||||
{
|
||||
const gchar *header0 = "statistics";
|
||||
const gchar *headerN = " ";
|
||||
stats delta;
|
||||
|
||||
delta.buffers = final->buffers - base->buffers;
|
||||
delta.bytes = final->bytes - base->bytes;
|
||||
delta.events = final->events - base->events;
|
||||
|
||||
g_print ("%s: (%s) %s: s:%g buffers:%" G_GINT64_FORMAT
|
||||
" bytes:%" G_GINT64_FORMAT
|
||||
" events:%" G_GINT64_FORMAT "\n",
|
||||
first ? header0 : headerN,
|
||||
name, type, time, final->buffers, final->bytes, final->events);
|
||||
g_print ("%s: (%s) %s: buf/s:%g B/s:%g e/s:%g B/buf:%g\n",
|
||||
headerN,
|
||||
name, type,
|
||||
delta.buffers / time,
|
||||
delta.bytes / time,
|
||||
delta.events / time, ((double) delta.bytes / (double) delta.buffers));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_print (GstStatistics * statistics)
|
||||
{
|
||||
const gchar *name;
|
||||
double elapsed;
|
||||
double last_elapsed;
|
||||
|
||||
g_return_if_fail (statistics != NULL);
|
||||
g_return_if_fail (GST_IS_STATISTICS (statistics));
|
||||
|
||||
name = gst_object_get_name (GST_OBJECT (statistics));
|
||||
if (!name) {
|
||||
name = "";
|
||||
}
|
||||
|
||||
elapsed = g_timer_elapsed (statistics->timer, NULL);
|
||||
last_elapsed = g_timer_elapsed (statistics->last_timer, NULL);
|
||||
|
||||
print_stats (1, name, "total", &zero_stats, &statistics->stats, elapsed);
|
||||
print_stats (0, name, "last", &statistics->last_stats, &statistics->stats,
|
||||
last_elapsed);
|
||||
statistics->last_stats = statistics->stats;
|
||||
g_timer_reset (statistics->last_timer);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstStatistics *statistics;
|
||||
gboolean update = FALSE;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
statistics = GST_STATISTICS (gst_pad_get_parent (pad));
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GstEvent *event = GST_EVENT (buf);
|
||||
|
||||
statistics->stats.events += 1;
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
|
||||
gst_element_set_eos (GST_ELEMENT (statistics));
|
||||
if (statistics->update_on_eos) {
|
||||
update = TRUE;
|
||||
}
|
||||
}
|
||||
if (statistics->update_freq.events) {
|
||||
statistics->update_count.events += 1;
|
||||
if (statistics->update_count.events == statistics->update_freq.events) {
|
||||
statistics->update_count.events = 0;
|
||||
update = TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
statistics->stats.buffers += 1;
|
||||
if (statistics->update_freq.buffers) {
|
||||
statistics->update_count.buffers += 1;
|
||||
if (statistics->update_count.buffers == statistics->update_freq.buffers) {
|
||||
statistics->update_count.buffers = 0;
|
||||
update = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
statistics->stats.bytes += GST_BUFFER_SIZE (buf);
|
||||
if (statistics->update_freq.bytes) {
|
||||
statistics->update_count.bytes += GST_BUFFER_SIZE (buf);
|
||||
if (statistics->update_count.bytes >= statistics->update_freq.bytes) {
|
||||
statistics->update_count.bytes = 0;
|
||||
update = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update) {
|
||||
if (statistics->update) {
|
||||
GST_DEBUG ("[%s]: pre update emit", GST_ELEMENT_NAME (statistics));
|
||||
g_signal_emit (G_OBJECT (statistics),
|
||||
gst_statistics_signals[SIGNAL_UPDATE], 0);
|
||||
GST_DEBUG ("[%s]: post update emit", GST_ELEMENT_NAME (statistics));
|
||||
}
|
||||
if (!statistics->silent) {
|
||||
gst_statistics_print (statistics);
|
||||
}
|
||||
}
|
||||
gst_pad_push (statistics->srcpad, GST_DATA (buf));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstStatistics *statistics;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_STATISTICS (object));
|
||||
|
||||
statistics = GST_STATISTICS (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_BUFFER_UPDATE_FREQ:
|
||||
statistics->update_freq.buffers = g_value_get_int64 (value);
|
||||
break;
|
||||
case ARG_BYTES_UPDATE_FREQ:
|
||||
statistics->update_freq.bytes = g_value_get_int64 (value);
|
||||
break;
|
||||
case ARG_EVENT_UPDATE_FREQ:
|
||||
statistics->update_freq.events = g_value_get_int64 (value);
|
||||
break;
|
||||
case ARG_UPDATE_ON_EOS:
|
||||
statistics->update_on_eos = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_UPDATE:
|
||||
statistics->update = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
statistics->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_statistics_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstStatistics *statistics;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_STATISTICS (object));
|
||||
|
||||
statistics = GST_STATISTICS (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_BUFFERS:
|
||||
g_value_set_int64 (value, statistics->stats.buffers);
|
||||
break;
|
||||
case ARG_BYTES:
|
||||
g_value_set_int64 (value, statistics->stats.bytes);
|
||||
break;
|
||||
case ARG_EVENTS:
|
||||
g_value_set_int64 (value, statistics->stats.events);
|
||||
break;
|
||||
case ARG_BUFFER_UPDATE_FREQ:
|
||||
g_value_set_int64 (value, statistics->update_freq.buffers);
|
||||
break;
|
||||
case ARG_BYTES_UPDATE_FREQ:
|
||||
g_value_set_int64 (value, statistics->update_freq.bytes);
|
||||
break;
|
||||
case ARG_EVENT_UPDATE_FREQ:
|
||||
g_value_set_int64 (value, statistics->update_freq.events);
|
||||
break;
|
||||
case ARG_UPDATE_ON_EOS:
|
||||
g_value_set_boolean (value, statistics->update_on_eos);
|
||||
break;
|
||||
case ARG_UPDATE:
|
||||
g_value_set_boolean (value, statistics->update);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, statistics->silent);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2001 David I. Lehn <dlehn@users.sourceforge.net>
|
||||
*
|
||||
* gststatistics.h:
|
||||
*
|
||||
* 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_STATISTICS_H__
|
||||
#define __GST_STATISTICS_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_STATISTICS \
|
||||
(gst_statistics_get_type())
|
||||
#define GST_STATISTICS(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STATISTICS,GstStatistics))
|
||||
#define GST_STATISTICS_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STATISTICS,GstStatisticsClass))
|
||||
#define GST_IS_STATISTICS(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STATISTICS))
|
||||
#define GST_IS_STATISTICS_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STATISTICS))
|
||||
|
||||
typedef struct _GstStatistics GstStatistics;
|
||||
typedef struct _GstStatisticsClass GstStatisticsClass;
|
||||
|
||||
typedef struct _stats stats;
|
||||
|
||||
struct _stats {
|
||||
gint64 buffers;
|
||||
gint64 bytes;
|
||||
gint64 events;
|
||||
};
|
||||
|
||||
struct _GstStatistics {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
GTimer *timer;
|
||||
GTimer *last_timer;
|
||||
|
||||
stats stats;
|
||||
stats last_stats;
|
||||
stats update_count;
|
||||
stats update_freq;
|
||||
|
||||
gboolean update_on_eos;
|
||||
gboolean update;
|
||||
gboolean silent;
|
||||
};
|
||||
|
||||
struct _GstStatisticsClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*update) (GstElement *element);
|
||||
};
|
||||
|
||||
GType gst_statistics_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_STATISTICS_H__ */
|
|
@ -1,362 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||
*
|
||||
* gsttee.c: Tee element, one in N out
|
||||
*
|
||||
* 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 "gsttee.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_tee_debug);
|
||||
#define GST_CAT_DEFAULT gst_tee_debug
|
||||
|
||||
GstElementDetails gst_tee_details = GST_ELEMENT_DETAILS ("Tee pipe fitting",
|
||||
"Generic",
|
||||
"1-to-N pipe fitting",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim.taymans@chello.be>");
|
||||
|
||||
/* Tee signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_SILENT,
|
||||
ARG_NUM_PADS,
|
||||
ARG_LAST_MESSAGE
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
GstStaticPadTemplate tee_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstTee, gst_tee, GstElement, GST_TYPE_ELEMENT, _do_init);
|
||||
|
||||
static GstPad *gst_tee_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * temp, const gchar * unused);
|
||||
|
||||
static void gst_tee_finalize (GObject * object);
|
||||
static void gst_tee_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_tee_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_tee_chain (GstPad * pad, GstData * _data);
|
||||
|
||||
|
||||
static void
|
||||
gst_tee_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 (&sinktemplate));
|
||||
gst_element_class_set_details (gstelement_class, &gst_tee_details);
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&tee_src_template));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_finalize (GObject * object)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (object);
|
||||
|
||||
g_free (tee->last_message);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_class_init (GstTeeClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
|
||||
g_param_spec_int ("num_pads", "num_pads", "num_pads",
|
||||
0, G_MAXINT, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent",
|
||||
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "last_message", "last_message",
|
||||
NULL, G_PARAM_READABLE));
|
||||
|
||||
|
||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tee_finalize);
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_tee_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_tee_get_property);
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_tee_request_new_pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_init (GstTee * tee)
|
||||
{
|
||||
tee->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||
"sink");
|
||||
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
|
||||
gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
|
||||
gst_pad_set_link_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
|
||||
gst_pad_set_getcaps_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
|
||||
tee->last_message = NULL;
|
||||
}
|
||||
|
||||
/* helper compare function */
|
||||
gint
|
||||
name_pad_compare (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
GstPad *pad = (GstPad *) a;
|
||||
gchar *name = (gchar *) b;
|
||||
|
||||
g_assert (GST_IS_PAD (pad));
|
||||
|
||||
return strcmp (name, gst_pad_get_name (pad)); /* returns 0 if match */
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_tee_getcaps (GstPad * _pad)
|
||||
{
|
||||
GstTee *tee = GST_TEE (gst_pad_get_parent (_pad));
|
||||
GstCaps *caps = gst_caps_new_any (), *tmp, *res;
|
||||
GstPad *pad;
|
||||
const GList *pads;
|
||||
|
||||
for (pads = gst_element_get_pad_list (GST_ELEMENT (tee));
|
||||
pads != NULL; pads = pads->next) {
|
||||
pad = GST_PAD (pads->data);
|
||||
if (pad == _pad)
|
||||
continue;
|
||||
|
||||
tmp = gst_pad_get_allowed_caps (pad);
|
||||
res = gst_caps_intersect (caps, tmp);
|
||||
gst_caps_free (tmp);
|
||||
gst_caps_free (caps);
|
||||
caps = res;
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_tee_link (GstPad * _pad, const GstCaps * caps)
|
||||
{
|
||||
GstTee *tee = GST_TEE (gst_pad_get_parent (_pad));
|
||||
GstPadLinkReturn res;
|
||||
GstPad *pad;
|
||||
const GList *pads;
|
||||
|
||||
GST_DEBUG_OBJECT (tee, "Forwarding link to all other pads");
|
||||
|
||||
for (pads = gst_element_get_pad_list (GST_ELEMENT (tee));
|
||||
pads != NULL; pads = pads->next) {
|
||||
pad = GST_PAD (pads->data);
|
||||
if (pad == _pad)
|
||||
continue;
|
||||
|
||||
res = gst_pad_try_set_caps (pad, caps);
|
||||
GST_DEBUG_OBJECT (tee, "Pad %s:%s gave response %d",
|
||||
GST_DEBUG_PAD_NAME (pad), res);
|
||||
if (GST_PAD_LINK_FAILED (res))
|
||||
return res;
|
||||
}
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
gchar *name;
|
||||
GstPad *srcpad;
|
||||
GstTee *tee;
|
||||
gint i = 0;
|
||||
const GList *pads;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TEE (element), NULL);
|
||||
|
||||
if (templ->direction != GST_PAD_SRC) {
|
||||
g_warning ("gsttee: request new pad that is not a SRC pad\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tee = GST_TEE (element);
|
||||
|
||||
/* try names in order and find one that's not in use atm */
|
||||
pads = gst_element_get_pad_list (element);
|
||||
|
||||
name = NULL;
|
||||
while (!name) {
|
||||
name = g_strdup_printf ("src%d", i);
|
||||
if (g_list_find_custom ((GList *) pads, (gconstpointer) name,
|
||||
name_pad_compare) != NULL) {
|
||||
/* this name is taken, use the next one */
|
||||
++i;
|
||||
g_free (name);
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
if (!tee->silent) {
|
||||
g_free (tee->last_message);
|
||||
tee->last_message = g_strdup_printf ("new pad %s", name);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
|
||||
srcpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
gst_pad_set_link_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_link));
|
||||
gst_pad_set_getcaps_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_getcaps));
|
||||
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
|
||||
GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
|
||||
|
||||
if (GST_PAD_CAPS (tee->sinkpad)) {
|
||||
gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
|
||||
}
|
||||
|
||||
return srcpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_TEE (object));
|
||||
|
||||
tee = GST_TEE (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_SILENT:
|
||||
tee->silent = g_value_get_boolean (value);
|
||||
g_object_notify (G_OBJECT (tee), "silent");
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail (GST_IS_TEE (object));
|
||||
|
||||
tee = GST_TEE (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_NUM_PADS:
|
||||
g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
g_value_set_boolean (value, tee->silent);
|
||||
break;
|
||||
case ARG_LAST_MESSAGE:
|
||||
g_value_set_string (value, tee->last_message);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_tee_chain:
|
||||
* @pad: the pad to follow
|
||||
* @buf: the buffer to pass
|
||||
*
|
||||
* Chain a buffer on a pad.
|
||||
*/
|
||||
static void
|
||||
gst_tee_chain (GstPad * pad, GstData * _data)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
GstTee *tee;
|
||||
const GList *pads;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
|
||||
tee = GST_TEE (gst_pad_get_parent (pad));
|
||||
|
||||
gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
|
||||
|
||||
pads = gst_element_get_pad_list (GST_ELEMENT (tee));
|
||||
|
||||
while (pads) {
|
||||
GstPad *outpad = GST_PAD (pads->data);
|
||||
|
||||
pads = g_list_next (pads);
|
||||
|
||||
if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC)
|
||||
continue;
|
||||
|
||||
if (!tee->silent) {
|
||||
g_free (tee->last_message);
|
||||
tee->last_message =
|
||||
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
|
||||
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (outpad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
|
||||
if (GST_PAD_IS_USABLE (outpad))
|
||||
gst_pad_push (outpad, GST_DATA (buf));
|
||||
else
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue