mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
remove moved dirs
Original commit message from CVS: remove moved dirs
This commit is contained in:
parent
233e55299e
commit
8c96632081
29 changed files with 0 additions and 8476 deletions
12
gst/elements/.gitignore
vendored
12
gst/elements/.gitignore
vendored
|
@ -1,12 +0,0 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
||||
*.bb
|
||||
*.bbg
|
||||
*.da
|
||||
*.def
|
||||
*.gcno
|
|
@ -1,46 +0,0 @@
|
|||
# FIXME:
|
||||
# need to get gstbufferstore.[ch] into its own lib, preferably
|
||||
# libs/gst/bufferstore
|
||||
# This requires building libs/gst before this dir, which we currently don't
|
||||
# do.
|
||||
|
||||
plugin_LTLIBRARIES = libgstelements.la
|
||||
|
||||
if HAVE_SYS_SOCKET_H
|
||||
GSTFDSRC = gstfdsrc.c
|
||||
else
|
||||
GSTFDSRC =
|
||||
endif
|
||||
|
||||
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||
libgstelements_la_SOURCES = \
|
||||
gstbufferstore.c \
|
||||
gstcapsfilter.c \
|
||||
gstfakesrc.c \
|
||||
gstfakesink.c \
|
||||
$(GSTFDSRC) \
|
||||
gstfilesink.c \
|
||||
gstfilesrc.c \
|
||||
gstidentity.c \
|
||||
gstelements.c \
|
||||
gsttee.c \
|
||||
gsttypefindelement.c
|
||||
|
||||
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstelements_la_LIBADD = \
|
||||
$(top_builddir)/gst/base/libgstbase-@GST_MAJORMINOR@.la \
|
||||
$(GST_OBJ_LIBS)
|
||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstbufferstore.h \
|
||||
gstfakesink.h \
|
||||
gstfakesrc.h \
|
||||
gstfdsrc.h \
|
||||
gstfilesink.h \
|
||||
gstfilesrc.h \
|
||||
gstidentity.h \
|
||||
gsttee.h \
|
||||
gsttypefindelement.h
|
||||
|
||||
EXTRA_DIST = gstfdsrc.c
|
|
@ -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, GstBufferStoreClass * g_class)
|
||||
{
|
||||
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_mini_object_ref (GST_MINI_OBJECT (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_mini_object_ref (GST_MINI_OBJECT (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_mini_object_unref (GST_MINI_OBJECT (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_mini_object_ref (GST_MINI_OBJECT (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_mini_object_ref (GST_MINI_OBJECT (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_mini_object_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_mini_object_ref (GST_MINI_OBJECT (ret));
|
||||
GST_LOG_OBJECT (store, "refcount %d", GST_MINI_OBJECT (ret)->refcount);
|
||||
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_mini_object_unref (GST_MINI_OBJECT (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>
|
||||
*
|
||||
* gstbufferstore.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,280 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
* 2005 David Schleef <ds@schleef.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "../gst-i18n-lib.h"
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasetransform.h>
|
||||
|
||||
|
||||
static GstElementDetails gst_capsfilter_details =
|
||||
GST_ELEMENT_DETAILS ("CapsFilter",
|
||||
"Generic",
|
||||
"Pass data without modification, limiting formats",
|
||||
"David Schleef <ds@schleef.org>");
|
||||
|
||||
|
||||
#define GST_TYPE_CAPSFILTER \
|
||||
(gst_capsfilter_get_type())
|
||||
#define GST_CAPSFILTER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAPSFILTER,GstCapsFilter))
|
||||
#define GST_CAPSFILTER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAPSFILTER,GstCapsFilterClass))
|
||||
#define GST_IS_CAPSFILTER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAPSFILTER))
|
||||
#define GST_IS_CAPSFILTER_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAPSFILTER))
|
||||
|
||||
typedef struct _GstCapsFilter GstCapsFilter;
|
||||
typedef struct _GstCapsFilterClass GstCapsFilterClass;
|
||||
|
||||
struct _GstCapsFilter
|
||||
{
|
||||
GstBaseTransform trans;
|
||||
|
||||
GstCaps *filter_caps;
|
||||
};
|
||||
|
||||
struct _GstCapsFilterClass
|
||||
{
|
||||
GstBaseTransformClass trans_class;
|
||||
};
|
||||
|
||||
GType gst_capsfilter_get_type (void);
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_FILTER_CAPS
|
||||
};
|
||||
|
||||
|
||||
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_capsfilter_debug);
|
||||
#define GST_CAT_DEFAULT gst_capsfilter_debug
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_capsfilter_debug, "capsfilter", 0, \
|
||||
"capsfilter element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstCapsFilter, gst_capsfilter, GstBaseTransform,
|
||||
GST_TYPE_BASE_TRANSFORM, _do_init);
|
||||
|
||||
|
||||
static void gst_capsfilter_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_capsfilter_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_capsfilter_dispose (GObject * object);
|
||||
static GstCaps *gst_capsfilter_transform_caps (GstBaseTransform * base,
|
||||
GstPadDirection direction, GstCaps * caps);
|
||||
static GstFlowReturn gst_capsfilter_transform_ip (GstBaseTransform * base,
|
||||
GstBuffer * buf);
|
||||
static GstFlowReturn gst_capsfilter_prepare_buf (GstBaseTransform * trans,
|
||||
GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
|
||||
|
||||
static void
|
||||
gst_capsfilter_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&srctemplate));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sinktemplate));
|
||||
gst_element_class_set_details (element_class, &gst_capsfilter_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_capsfilter_class_init (GstCapsFilterClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstBaseTransformClass *trans_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gobject_class->set_property = gst_capsfilter_set_property;
|
||||
gobject_class->get_property = gst_capsfilter_get_property;
|
||||
gobject_class->dispose = gst_capsfilter_dispose;
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTER_CAPS,
|
||||
g_param_spec_boxed ("caps", _("Filter caps"),
|
||||
_("Restrict the possible allowed capabilities (NULL means ANY)"),
|
||||
GST_TYPE_CAPS, G_PARAM_READWRITE));
|
||||
|
||||
trans_class = (GstBaseTransformClass *) klass;
|
||||
trans_class->transform_caps = gst_capsfilter_transform_caps;
|
||||
trans_class->transform_ip = gst_capsfilter_transform_ip;
|
||||
trans_class->prepare_output_buffer = gst_capsfilter_prepare_buf;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_capsfilter_init (GstCapsFilter * filter, GstCapsFilterClass * g_class)
|
||||
{
|
||||
filter->filter_caps = gst_caps_new_any ();
|
||||
}
|
||||
|
||||
static void
|
||||
gst_capsfilter_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FILTER_CAPS:{
|
||||
GstCaps *new_caps;
|
||||
GstCaps *old_caps;
|
||||
const GstCaps *new_caps_val = gst_value_get_caps (value);
|
||||
|
||||
if (new_caps_val == NULL) {
|
||||
new_caps = gst_caps_new_any ();
|
||||
} else {
|
||||
new_caps = gst_caps_copy (new_caps_val);
|
||||
}
|
||||
|
||||
old_caps = capsfilter->filter_caps;
|
||||
capsfilter->filter_caps = new_caps;
|
||||
gst_caps_unref (old_caps);
|
||||
|
||||
GST_DEBUG_OBJECT (capsfilter, "set new caps %" GST_PTR_FORMAT, new_caps);
|
||||
|
||||
/* FIXME: Need to activate these caps on the pads */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FILTER_CAPS:
|
||||
gst_value_set_caps (value, capsfilter->filter_caps);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_capsfilter_dispose (GObject * object)
|
||||
{
|
||||
GstCapsFilter *filter = GST_CAPSFILTER (object);
|
||||
|
||||
gst_caps_replace (&filter->filter_caps, NULL);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_capsfilter_transform_caps (GstBaseTransform * base,
|
||||
GstPadDirection direction, GstCaps * caps)
|
||||
{
|
||||
GstCapsFilter *capsfilter = GST_CAPSFILTER (base);
|
||||
GstCaps *ret;
|
||||
|
||||
ret = gst_caps_intersect (caps, capsfilter->filter_caps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_capsfilter_transform_ip (GstBaseTransform * base, GstBuffer * buf)
|
||||
{
|
||||
/* No actual work here. It's all done in the prepare output buffer
|
||||
* func. */
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
/* Output buffer preparation... if the buffer has no caps, and
|
||||
* our allowed output caps is fixed, then give the caps to the
|
||||
* buffer.
|
||||
* This ensures that outgoing buffers have caps if we can, so
|
||||
* that pipelines like:
|
||||
* gst-launch filesrc location=rawsamples.raw !
|
||||
* audio/x-raw-int,width=16,depth=16,rate=48000,channels=2,
|
||||
* endianness=4321,signed='(boolean)'true ! alsasink
|
||||
* will work.
|
||||
*/
|
||||
static GstFlowReturn
|
||||
gst_capsfilter_prepare_buf (GstBaseTransform * trans, GstBuffer * input,
|
||||
gint size, GstCaps * caps, GstBuffer ** buf)
|
||||
{
|
||||
if (GST_BUFFER_CAPS (input) != NULL) {
|
||||
/* Output buffer already has caps */
|
||||
GST_DEBUG_OBJECT (trans, "Input buffer already has caps");
|
||||
gst_buffer_ref (input);
|
||||
*buf = input;
|
||||
} else {
|
||||
/* Buffer has no caps. See if the output pad only supports fixed caps */
|
||||
GstCaps *out_caps;
|
||||
|
||||
out_caps = GST_PAD_CAPS (trans->srcpad);
|
||||
|
||||
if (out_caps != NULL) {
|
||||
gst_caps_ref (out_caps);
|
||||
} else {
|
||||
out_caps = gst_pad_get_allowed_caps (trans->srcpad);
|
||||
g_return_val_if_fail (out_caps != NULL, GST_FLOW_ERROR);
|
||||
}
|
||||
|
||||
if (gst_caps_is_fixed (out_caps) && !gst_caps_is_empty (out_caps)) {
|
||||
GST_DEBUG_OBJECT (trans, "Have fixed output caps %"
|
||||
GST_PTR_FORMAT " to apply to buffer with no caps", out_caps);
|
||||
if (gst_buffer_is_writable (input)) {
|
||||
gst_buffer_ref (input);
|
||||
*buf = input;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (trans, "Creating sub-buffer and setting caps");
|
||||
*buf = gst_buffer_create_sub (input, 0, GST_BUFFER_SIZE (input));
|
||||
}
|
||||
GST_BUFFER_CAPS (*buf) = out_caps;
|
||||
|
||||
if (GST_PAD_CAPS (trans->srcpad) == NULL)
|
||||
gst_pad_set_caps (trans->srcpad, out_caps);
|
||||
} else {
|
||||
gst_caps_unref (out_caps);
|
||||
}
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
|
@ -1,84 +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 "gstfakesink.h"
|
||||
#include "gstfakesrc.h"
|
||||
#include "gstfdsrc.h"
|
||||
#include "gstfilesink.h"
|
||||
#include "gstfilesrc.h"
|
||||
#include "gstidentity.h"
|
||||
#include "gsttee.h"
|
||||
#include "gsttypefindelement.h"
|
||||
|
||||
struct _elements_entry
|
||||
{
|
||||
gchar *name;
|
||||
guint rank;
|
||||
GType (*type) (void);
|
||||
};
|
||||
|
||||
|
||||
/* this declaration is here because there's no gstcapsfilter.h */
|
||||
extern GType gst_capsfilter_get_type (void);
|
||||
|
||||
static struct _elements_entry _elements[] = {
|
||||
{"capsfilter", GST_RANK_NONE, gst_capsfilter_get_type},
|
||||
{"fakesrc", GST_RANK_NONE, gst_fake_src_get_type},
|
||||
{"fakesink", GST_RANK_NONE, gst_fake_sink_get_type},
|
||||
#if HAVE_SYS_SOCKET_H
|
||||
{"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
|
||||
#endif
|
||||
{"filesrc", GST_RANK_NONE, gst_file_src_get_type},
|
||||
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
||||
{"filesink", GST_RANK_NONE, gst_file_sink_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_NAME, GST_PACKAGE_ORIGIN);
|
|
@ -1,437 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* SECTION:gstfakesink
|
||||
* @short_description: black hole for data
|
||||
* @see_also: #GstFakeSrc
|
||||
*
|
||||
* Dummy sink that swallows everything.
|
||||
*/
|
||||
|
||||
#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_fake_sink_debug);
|
||||
#define GST_CAT_DEFAULT gst_fake_sink_debug
|
||||
|
||||
static GstElementDetails gst_fake_sink_details =
|
||||
GST_ELEMENT_DETAILS ("Fake Sink",
|
||||
"Sink",
|
||||
"Black hole for data",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim Taymans <wim@fluendo.com>, "
|
||||
"Mr. 'frag-me-more' Vanderwingo <wingo@fluendo.com>");
|
||||
|
||||
|
||||
/* FakeSink signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
SIGNAL_HANDOFF,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define DEFAULT_SYNC FALSE
|
||||
|
||||
#define DEFAULT_STATE_ERROR FAKE_SINK_STATE_ERROR_NONE
|
||||
#define DEFAULT_SILENT FALSE
|
||||
#define DEFAULT_DUMP FALSE
|
||||
#define DEFAULT_SIGNAL_HANDOFFS FALSE
|
||||
#define DEFAULT_LAST_MESSAGE NULL
|
||||
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
|
||||
#define DEFAULT_CAN_ACTIVATE_PULL FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_STATE_ERROR,
|
||||
PROP_SILENT,
|
||||
PROP_DUMP,
|
||||
PROP_SIGNAL_HANDOFFS,
|
||||
PROP_LAST_MESSAGE,
|
||||
PROP_CAN_ACTIVATE_PUSH,
|
||||
PROP_CAN_ACTIVATE_PULL
|
||||
};
|
||||
|
||||
#define GST_TYPE_FAKE_SINK_STATE_ERROR (gst_fake_sink_state_error_get_type())
|
||||
static GType
|
||||
gst_fake_sink_state_error_get_type (void)
|
||||
{
|
||||
static GType fakesink_state_error_type = 0;
|
||||
static GEnumValue fakesink_state_error[] = {
|
||||
{FAKE_SINK_STATE_ERROR_NONE, "No state change errors", "none"},
|
||||
{FAKE_SINK_STATE_ERROR_NULL_READY,
|
||||
"Fail state change from NULL to READY", "null-to-ready"},
|
||||
{FAKE_SINK_STATE_ERROR_READY_PAUSED,
|
||||
"Fail state change from READY to PAUSED", "ready-to-paused"},
|
||||
{FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
|
||||
"Fail state change from PAUSED to PLAYING", "paused-to-playing"},
|
||||
{FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
|
||||
"Fail state change from PLAYING to PAUSED", "playing-to-paused"},
|
||||
{FAKE_SINK_STATE_ERROR_PAUSED_READY,
|
||||
"Fail state change from PAUSED to READY", "paused-to-ready"},
|
||||
{FAKE_SINK_STATE_ERROR_READY_NULL,
|
||||
"Fail state change from READY to NULL", "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_fake_sink_debug, "fakesink", 0, "fakesink element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFakeSink, gst_fake_sink, GstBaseSink,
|
||||
GST_TYPE_BASE_SINK, _do_init);
|
||||
|
||||
static void gst_fake_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fake_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstStateChangeReturn gst_fake_sink_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static GstFlowReturn gst_fake_sink_preroll (GstBaseSink * bsink,
|
||||
GstBuffer * buffer);
|
||||
static GstFlowReturn gst_fake_sink_render (GstBaseSink * bsink,
|
||||
GstBuffer * buffer);
|
||||
static gboolean gst_fake_sink_event (GstBaseSink * bsink, GstEvent * event);
|
||||
|
||||
static guint gst_fake_sink_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gst_fake_sink_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_fake_sink_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_sink_class_init (GstFakeSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSinkClass *gstbase_sink_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbase_sink_class = (GstBaseSinkClass *) klass;
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fake_sink_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fake_sink_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_STATE_ERROR,
|
||||
g_param_spec_enum ("state_error", "State Error",
|
||||
"Generate a state change error", GST_TYPE_FAKE_SINK_STATE_ERROR,
|
||||
DEFAULT_STATE_ERROR, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "Last Message",
|
||||
"The message describing current status", DEFAULT_LAST_MESSAGE,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_HANDOFFS,
|
||||
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
|
||||
"Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
|
||||
g_param_spec_boolean ("silent", "Silent",
|
||||
"Don't produce last_message events", DEFAULT_SILENT,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump received bytes to stdout",
|
||||
DEFAULT_DUMP, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
PROP_CAN_ACTIVATE_PUSH,
|
||||
g_param_spec_boolean ("can-activate-push", "Can activate push",
|
||||
"Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
PROP_CAN_ACTIVATE_PULL,
|
||||
g_param_spec_boolean ("can-activate-pull", "Can activate pull",
|
||||
"Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GstFakeSink::handoff:
|
||||
* @fakesink: the fakesink instance
|
||||
* @buffer: the buffer that just has been received
|
||||
* @pad: the pad that received it
|
||||
*
|
||||
* This signal gets emitted before unreffing the buffer.
|
||||
*/
|
||||
gst_fake_sink_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__OBJECT_OBJECT, G_TYPE_NONE, 2,
|
||||
GST_TYPE_BUFFER, GST_TYPE_PAD);
|
||||
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_fake_sink_change_state);
|
||||
|
||||
gstbase_sink_class->event = GST_DEBUG_FUNCPTR (gst_fake_sink_event);
|
||||
gstbase_sink_class->preroll = GST_DEBUG_FUNCPTR (gst_fake_sink_preroll);
|
||||
gstbase_sink_class->render = GST_DEBUG_FUNCPTR (gst_fake_sink_render);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_sink_init (GstFakeSink * fakesink, GstFakeSinkClass * g_class)
|
||||
{
|
||||
fakesink->silent = DEFAULT_SILENT;
|
||||
fakesink->dump = DEFAULT_DUMP;
|
||||
GST_BASE_SINK (fakesink)->sync = DEFAULT_SYNC;
|
||||
fakesink->last_message = g_strdup (DEFAULT_LAST_MESSAGE);
|
||||
fakesink->state_error = DEFAULT_STATE_ERROR;
|
||||
fakesink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
sink = GST_FAKE_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SILENT:
|
||||
sink->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_STATE_ERROR:
|
||||
sink->state_error = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_DUMP:
|
||||
sink->dump = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_SIGNAL_HANDOFFS:
|
||||
sink->signal_handoffs = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PUSH:
|
||||
GST_BASE_SINK (sink)->can_activate_push = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PULL:
|
||||
GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_sink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSink *sink;
|
||||
|
||||
sink = GST_FAKE_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_STATE_ERROR:
|
||||
g_value_set_enum (value, sink->state_error);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
g_value_set_boolean (value, sink->silent);
|
||||
break;
|
||||
case PROP_DUMP:
|
||||
g_value_set_boolean (value, sink->dump);
|
||||
break;
|
||||
case PROP_SIGNAL_HANDOFFS:
|
||||
g_value_set_boolean (value, sink->signal_handoffs);
|
||||
break;
|
||||
case PROP_LAST_MESSAGE:
|
||||
GST_OBJECT_LOCK (sink);
|
||||
g_value_set_string (value, sink->last_message);
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PUSH:
|
||||
g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_push);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PULL:
|
||||
g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fake_sink_event (GstBaseSink * bsink, GstEvent * event)
|
||||
{
|
||||
GstFakeSink *sink = GST_FAKE_SINK (bsink);
|
||||
|
||||
if (!sink->silent) {
|
||||
const GstStructure *s;
|
||||
gchar *sstr;
|
||||
|
||||
GST_OBJECT_LOCK (sink);
|
||||
g_free (sink->last_message);
|
||||
|
||||
if ((s = gst_event_get_structure (event)))
|
||||
sstr = gst_structure_to_string (s);
|
||||
else
|
||||
sstr = g_strdup ("");
|
||||
|
||||
sink->last_message =
|
||||
g_strdup_printf ("event ******* E (type: %d, %s) %p",
|
||||
GST_EVENT_TYPE (event), sstr, event);
|
||||
g_free (sstr);
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_fake_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
|
||||
{
|
||||
GstFakeSink *sink = GST_FAKE_SINK (bsink);
|
||||
|
||||
if (!sink->silent) {
|
||||
GST_OBJECT_LOCK (sink);
|
||||
g_free (sink->last_message);
|
||||
|
||||
sink->last_message = g_strdup_printf ("preroll ******* ");
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_fake_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||
{
|
||||
GstFakeSink *sink = GST_FAKE_SINK (bsink);
|
||||
|
||||
if (!sink->silent) {
|
||||
gchar ts_str[64], dur_str[64];
|
||||
|
||||
GST_OBJECT_LOCK (sink);
|
||||
g_free (sink->last_message);
|
||||
|
||||
if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
|
||||
g_snprintf (ts_str, sizeof (ts_str), "%" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||
} else {
|
||||
g_strlcpy (ts_str, "none", sizeof (ts_str));
|
||||
}
|
||||
|
||||
if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) {
|
||||
g_snprintf (dur_str, sizeof (dur_str), "%" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
|
||||
} else {
|
||||
g_strlcpy (dur_str, "none", sizeof (dur_str));
|
||||
}
|
||||
|
||||
sink->last_message =
|
||||
g_strdup_printf ("chain ******* < (%5d bytes, timestamp: %s"
|
||||
", duration: %s, offset: %" G_GINT64_FORMAT ", offset_end: %"
|
||||
G_GINT64_FORMAT ", flags: %d) %p", GST_BUFFER_SIZE (buf), ts_str,
|
||||
dur_str, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf),
|
||||
GST_MINI_OBJECT (buf)->flags, buf);
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
|
||||
g_object_notify (G_OBJECT (sink), "last_message");
|
||||
}
|
||||
if (sink->signal_handoffs)
|
||||
g_signal_emit (G_OBJECT (sink), gst_fake_sink_signals[SIGNAL_HANDOFF], 0,
|
||||
buf, bsink->sinkpad);
|
||||
|
||||
if (sink->dump) {
|
||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_fake_sink_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
GstFakeSink *fakesink = GST_FAKE_SINK (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_NULL_READY)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_READY_PAUSED)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_PAUSED_PLAYING)
|
||||
goto error;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_PLAYING_PAUSED)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_PAUSED_READY)
|
||||
goto error;
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_READY_NULL)
|
||||
goto error;
|
||||
GST_OBJECT_LOCK (fakesink);
|
||||
g_free (fakesink->last_message);
|
||||
fakesink->last_message = NULL;
|
||||
GST_OBJECT_UNLOCK (fakesink);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERROR */
|
||||
error:
|
||||
GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
|
@ -1,95 +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_FAKE_SINK_H__
|
||||
#define __GST_FAKE_SINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_FAKE_SINK \
|
||||
(gst_fake_sink_get_type())
|
||||
#define GST_FAKE_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FAKE_SINK,GstFakeSink))
|
||||
#define GST_FAKE_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FAKE_SINK,GstFakeSinkClass))
|
||||
#define GST_IS_FAKE_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FAKE_SINK))
|
||||
#define GST_IS_FAKE_SINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FAKE_SINK))
|
||||
|
||||
/**
|
||||
* GstFakeSinkStateError:
|
||||
* @FAKE_SINK_STATE_ERROR_NONE: no error
|
||||
* @FAKE_SINK_STATE_ERROR_NULL_READY: cause the NULL to READY state change to fail
|
||||
* @FAKE_SINK_STATE_ERROR_READY_PAUSED: cause the READY to PAUSED state change to fail:
|
||||
* @FAKE_SINK_STATE_ERROR_PAUSED_PLAYING: cause the PAUSED to PLAYING state change to fail:
|
||||
* @FAKE_SINK_STATE_ERROR_PLAYING_PAUSED: cause the PLAYING to PAUSED state change to fail:
|
||||
* @FAKE_SINK_STATE_ERROR_PAUSED_READY: cause the PAUSED to READY state change to fail:
|
||||
* @FAKE_SINK_STATE_ERROR_READY_NULL: cause the READY to NULL state change to fail:
|
||||
*
|
||||
* Possible state change errors for the state-error property.
|
||||
*/
|
||||
typedef enum {
|
||||
FAKE_SINK_STATE_ERROR_NONE = 0,
|
||||
FAKE_SINK_STATE_ERROR_NULL_READY,
|
||||
FAKE_SINK_STATE_ERROR_READY_PAUSED,
|
||||
FAKE_SINK_STATE_ERROR_PAUSED_PLAYING,
|
||||
FAKE_SINK_STATE_ERROR_PLAYING_PAUSED,
|
||||
FAKE_SINK_STATE_ERROR_PAUSED_READY,
|
||||
FAKE_SINK_STATE_ERROR_READY_NULL
|
||||
} GstFakeSinkStateError;
|
||||
|
||||
typedef struct _GstFakeSink GstFakeSink;
|
||||
typedef struct _GstFakeSinkClass GstFakeSinkClass;
|
||||
|
||||
/**
|
||||
* GstFakeSink:
|
||||
*
|
||||
* The opaque #GstFakeSink data structure.
|
||||
*/
|
||||
struct _GstFakeSink {
|
||||
GstBaseSink element;
|
||||
|
||||
gboolean silent;
|
||||
gboolean dump;
|
||||
gboolean signal_handoffs;
|
||||
GstFakeSinkStateError state_error;
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstFakeSinkClass {
|
||||
GstBaseSinkClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
|
||||
};
|
||||
|
||||
GType gst_fake_sink_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FAKE_SINK_H__ */
|
|
@ -1,804 +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.
|
||||
*/
|
||||
/**
|
||||
* SECTION:gstfakesrc
|
||||
* @short_description: Push empty (no data) buffers around
|
||||
* @see_also: #GstFakeSink
|
||||
*
|
||||
* Dummy source that generates empty buffers.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstfakesrc.h"
|
||||
#include <gst/gstmarshal.h>
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_fake_src_debug);
|
||||
#define GST_CAT_DEFAULT gst_fake_src_debug
|
||||
|
||||
static GstElementDetails gst_fake_src_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
|
||||
};
|
||||
|
||||
#define DEFAULT_OUTPUT FAKE_SRC_FIRST_LAST_LOOP
|
||||
#define DEFAULT_DATA FAKE_SRC_DATA_ALLOCATE
|
||||
#define DEFAULT_SIZETYPE FAKE_SRC_SIZETYPE_EMPTY
|
||||
#define DEFAULT_SIZEMIN 0
|
||||
#define DEFAULT_SIZEMAX 4096
|
||||
#define DEFAULT_FILLTYPE FAKE_SRC_FILLTYPE_ZERO
|
||||
#define DEFAULT_DATARATE 0
|
||||
#define DEFAULT_SYNC FALSE
|
||||
#define DEFAULT_PATTERN NULL
|
||||
#define DEFAULT_EOS FALSE
|
||||
#define DEFAULT_SIGNAL_HANDOFFS FALSE
|
||||
#define DEFAULT_SILENT FALSE
|
||||
#define DEFAULT_DUMP FALSE
|
||||
#define DEFAULT_PARENTSIZE 4096*10
|
||||
#define DEFAULT_CAN_ACTIVATE_PULL TRUE
|
||||
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_OUTPUT,
|
||||
PROP_DATA,
|
||||
PROP_SIZETYPE,
|
||||
PROP_SIZEMIN,
|
||||
PROP_SIZEMAX,
|
||||
PROP_FILLTYPE,
|
||||
PROP_DATARATE,
|
||||
PROP_SYNC,
|
||||
PROP_PATTERN,
|
||||
PROP_EOS,
|
||||
PROP_SIGNAL_HANDOFFS,
|
||||
PROP_SILENT,
|
||||
PROP_DUMP,
|
||||
PROP_PARENTSIZE,
|
||||
PROP_LAST_MESSAGE,
|
||||
PROP_CAN_ACTIVATE_PULL,
|
||||
PROP_CAN_ACTIVATE_PUSH,
|
||||
PROP_IS_LIVE
|
||||
};
|
||||
|
||||
/* not implemented
|
||||
#define GST_TYPE_FAKE_SRC_OUTPUT (gst_fake_src_output_get_type())
|
||||
static GType
|
||||
gst_fake_src_output_get_type (void)
|
||||
{
|
||||
static GType fakesrc_output_type = 0;
|
||||
static GEnumValue fakesrc_output[] = {
|
||||
{FAKE_SRC_FIRST_LAST_LOOP, "1", "First-Last loop"},
|
||||
{FAKE_SRC_LAST_FIRST_LOOP, "2", "Last-First loop"},
|
||||
{FAKE_SRC_PING_PONG, "3", "Ping-Pong"},
|
||||
{FAKE_SRC_ORDERED_RANDOM, "4", "Ordered Random"},
|
||||
{FAKE_SRC_RANDOM, "5", "Random"},
|
||||
{FAKE_SRC_PATTERN_LOOP, "6", "Patttern loop"},
|
||||
{FAKE_SRC_PING_PONG_PATTERN, "7", "Ping-Pong Pattern"},
|
||||
{FAKE_SRC_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_FAKE_SRC_DATA (gst_fake_src_data_get_type())
|
||||
static GType
|
||||
gst_fake_src_data_get_type (void)
|
||||
{
|
||||
static GType fakesrc_data_type = 0;
|
||||
static GEnumValue fakesrc_data[] = {
|
||||
{FAKE_SRC_DATA_ALLOCATE, "Allocate data", "allocate"},
|
||||
{FAKE_SRC_DATA_SUBBUFFER, "Subbuffer data", "subbuffer"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!fakesrc_data_type) {
|
||||
fakesrc_data_type =
|
||||
g_enum_register_static ("GstFakeSrcDataType", fakesrc_data);
|
||||
}
|
||||
return fakesrc_data_type;
|
||||
}
|
||||
|
||||
#define GST_TYPE_FAKE_SRC_SIZETYPE (gst_fake_src_sizetype_get_type())
|
||||
static GType
|
||||
gst_fake_src_sizetype_get_type (void)
|
||||
{
|
||||
static GType fakesrc_sizetype_type = 0;
|
||||
static GEnumValue fakesrc_sizetype[] = {
|
||||
{FAKE_SRC_SIZETYPE_EMPTY, "Send empty buffers", "empty"},
|
||||
{FAKE_SRC_SIZETYPE_FIXED, "Fixed size buffers (sizemax sized)", "fixed"},
|
||||
{FAKE_SRC_SIZETYPE_RANDOM,
|
||||
"Random sized buffers (sizemin <= size <= sizemax)", "random"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!fakesrc_sizetype_type) {
|
||||
fakesrc_sizetype_type =
|
||||
g_enum_register_static ("GstFakeSrcSizeType", fakesrc_sizetype);
|
||||
}
|
||||
return fakesrc_sizetype_type;
|
||||
}
|
||||
|
||||
#define GST_TYPE_FAKE_SRC_FILLTYPE (gst_fake_src_filltype_get_type())
|
||||
static GType
|
||||
gst_fake_src_filltype_get_type (void)
|
||||
{
|
||||
static GType fakesrc_filltype_type = 0;
|
||||
static GEnumValue fakesrc_filltype[] = {
|
||||
{FAKE_SRC_FILLTYPE_NOTHING, "Leave data as malloced", "nothing"},
|
||||
{FAKE_SRC_FILLTYPE_ZERO, "Fill buffers with zeros", "zero"},
|
||||
{FAKE_SRC_FILLTYPE_RANDOM, "Fill buffers with random crap", "random"},
|
||||
{FAKE_SRC_FILLTYPE_PATTERN, "Fill buffers with pattern 0x00 -> 0xff",
|
||||
"pattern"},
|
||||
{FAKE_SRC_FILLTYPE_PATTERN_CONT,
|
||||
"Fill buffers with pattern 0x00 -> 0xff that spans buffers",
|
||||
"pattern-span"},
|
||||
{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_fake_src_debug, "fakesrc", 0, "fakesrc element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFakeSrc, gst_fake_src, GstBaseSrc, GST_TYPE_BASE_SRC,
|
||||
_do_init);
|
||||
|
||||
static void gst_fake_src_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_fake_src_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static gboolean gst_fake_src_start (GstBaseSrc * basesrc);
|
||||
static gboolean gst_fake_src_stop (GstBaseSrc * basesrc);
|
||||
static gboolean gst_fake_src_is_seekable (GstBaseSrc * basesrc);
|
||||
|
||||
static gboolean gst_fake_src_event_handler (GstBaseSrc * src, GstEvent * event);
|
||||
static GstFlowReturn gst_fake_src_create (GstBaseSrc * src, guint64 offset,
|
||||
guint length, GstBuffer ** buf);
|
||||
|
||||
static guint gst_fake_src_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gst_fake_src_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_fake_src_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_src_class_init (GstFakeSrcClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSrcClass *gstbase_src_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbase_src_class = (GstBaseSrcClass *) klass;
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fake_src_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fake_src_get_property);
|
||||
|
||||
/*
|
||||
FIXME: this is not implemented; would make sense once basesrc and fakesrc
|
||||
support multiple pads
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_OUTPUT,
|
||||
g_param_spec_enum ("output", "output", "Output method (currently unused)",
|
||||
GST_TYPE_FAKE_SRC_OUTPUT, DEFAULT_OUTPUT, G_PARAM_READWRITE));
|
||||
*/
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DATA,
|
||||
g_param_spec_enum ("data", "data", "Data allocation method",
|
||||
GST_TYPE_FAKE_SRC_DATA, DEFAULT_DATA, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIZETYPE,
|
||||
g_param_spec_enum ("sizetype", "sizetype",
|
||||
"How to determine buffer sizes", GST_TYPE_FAKE_SRC_SIZETYPE,
|
||||
DEFAULT_SIZETYPE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_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), PROP_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), PROP_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), PROP_FILLTYPE,
|
||||
g_param_spec_enum ("filltype", "filltype",
|
||||
"How to fill the buffer, if at all", GST_TYPE_FAKE_SRC_FILLTYPE,
|
||||
DEFAULT_FILLTYPE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_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), PROP_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), PROP_PATTERN,
|
||||
g_param_spec_string ("pattern", "pattern", "pattern", DEFAULT_PATTERN,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_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), PROP_SILENT,
|
||||
g_param_spec_boolean ("silent", "Silent",
|
||||
"Don't produce last_message events", DEFAULT_SILENT,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_HANDOFFS,
|
||||
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
|
||||
"Send a signal before pushing the buffer", DEFAULT_SIGNAL_HANDOFFS,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump produced bytes to stdout",
|
||||
DEFAULT_DUMP, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
PROP_CAN_ACTIVATE_PUSH,
|
||||
g_param_spec_boolean ("can-activate-push", "Can activate push",
|
||||
"Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
PROP_CAN_ACTIVATE_PULL,
|
||||
g_param_spec_boolean ("can-activate-pull", "Can activate pull",
|
||||
"Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_IS_LIVE,
|
||||
g_param_spec_boolean ("is-live", "Is this a live source",
|
||||
"True if the element cannot produce data in PAUSED", FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
/**
|
||||
* GstFakeSrc::handoff:
|
||||
* @fakesrc: the fakesrc instance
|
||||
* @buffer: the buffer that will be pushed
|
||||
* @pad: the pad that will sent it
|
||||
*
|
||||
* This signal gets emitted before sending the buffer.
|
||||
*/
|
||||
gst_fake_src_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__OBJECT_OBJECT, G_TYPE_NONE, 2, GST_TYPE_BUFFER,
|
||||
GST_TYPE_PAD);
|
||||
|
||||
gstbase_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fake_src_is_seekable);
|
||||
gstbase_src_class->start = GST_DEBUG_FUNCPTR (gst_fake_src_start);
|
||||
gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gst_fake_src_stop);
|
||||
gstbase_src_class->event = GST_DEBUG_FUNCPTR (gst_fake_src_event_handler);
|
||||
gstbase_src_class->create = GST_DEBUG_FUNCPTR (gst_fake_src_create);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_src_init (GstFakeSrc * fakesrc, GstFakeSrcClass * g_class)
|
||||
{
|
||||
fakesrc->output = FAKE_SRC_FIRST_LAST_LOOP;
|
||||
fakesrc->buffer_count = 0;
|
||||
fakesrc->silent = DEFAULT_SILENT;
|
||||
fakesrc->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
|
||||
fakesrc->dump = DEFAULT_DUMP;
|
||||
fakesrc->pattern_byte = 0x00;
|
||||
fakesrc->data = FAKE_SRC_DATA_ALLOCATE;
|
||||
fakesrc->sizetype = FAKE_SRC_SIZETYPE_EMPTY;
|
||||
fakesrc->filltype = FAKE_SRC_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 gboolean
|
||||
gst_fake_src_event_handler (GstBaseSrc * basesrc, GstEvent * event)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
|
||||
src = GST_FAKE_SRC (basesrc);
|
||||
|
||||
if (!src->silent) {
|
||||
const GstStructure *s;
|
||||
gchar *sstr;
|
||||
|
||||
GST_OBJECT_LOCK (src);
|
||||
g_free (src->last_message);
|
||||
|
||||
if ((s = gst_event_get_structure (event)))
|
||||
sstr = gst_structure_to_string (s);
|
||||
else
|
||||
sstr = g_strdup ("");
|
||||
|
||||
src->last_message =
|
||||
g_strdup_printf ("event ******* E (type: %d, %s) %p",
|
||||
GST_EVENT_TYPE (event), sstr, event);
|
||||
g_free (sstr);
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
g_object_notify (G_OBJECT (src), "last_message");
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_src_alloc_parent (GstFakeSrc * src)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
buf = gst_buffer_new ();
|
||||
GST_BUFFER_DATA (buf) = g_malloc (src->parentsize);
|
||||
GST_BUFFER_MALLOCDATA (buf) = GST_BUFFER_DATA (buf);
|
||||
GST_BUFFER_SIZE (buf) = src->parentsize;
|
||||
|
||||
src->parent = buf;
|
||||
src->parentoffset = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_src_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
GstBaseSrc *basesrc;
|
||||
|
||||
src = GST_FAKE_SRC (object);
|
||||
basesrc = GST_BASE_SRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_OUTPUT:
|
||||
g_warning ("not yet implemented");
|
||||
break;
|
||||
case PROP_DATA:
|
||||
src->data = g_value_get_enum (value);
|
||||
|
||||
if (src->data == FAKE_SRC_DATA_SUBBUFFER) {
|
||||
if (!src->parent)
|
||||
gst_fake_src_alloc_parent (src);
|
||||
} else {
|
||||
if (src->parent) {
|
||||
gst_buffer_unref (src->parent);
|
||||
src->parent = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_SIZETYPE:
|
||||
src->sizetype = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_SIZEMIN:
|
||||
src->sizemin = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_SIZEMAX:
|
||||
src->sizemax = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_PARENTSIZE:
|
||||
src->parentsize = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_FILLTYPE:
|
||||
src->filltype = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_DATARATE:
|
||||
src->datarate = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_SYNC:
|
||||
src->sync = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_PATTERN:
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
src->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_SIGNAL_HANDOFFS:
|
||||
src->signal_handoffs = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_DUMP:
|
||||
src->dump = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PUSH:
|
||||
g_return_if_fail (!GST_OBJECT_FLAG_IS_SET (object, GST_BASE_SRC_STARTED));
|
||||
GST_BASE_SRC (src)->can_activate_push = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PULL:
|
||||
g_return_if_fail (!GST_OBJECT_FLAG_IS_SET (object, GST_BASE_SRC_STARTED));
|
||||
src->can_activate_pull = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_IS_LIVE:
|
||||
gst_base_src_set_live (basesrc, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_src_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
GstBaseSrc *basesrc;
|
||||
|
||||
g_return_if_fail (GST_IS_FAKE_SRC (object));
|
||||
|
||||
src = GST_FAKE_SRC (object);
|
||||
basesrc = GST_BASE_SRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_OUTPUT:
|
||||
g_value_set_enum (value, src->output);
|
||||
break;
|
||||
case PROP_DATA:
|
||||
g_value_set_enum (value, src->data);
|
||||
break;
|
||||
case PROP_SIZETYPE:
|
||||
g_value_set_enum (value, src->sizetype);
|
||||
break;
|
||||
case PROP_SIZEMIN:
|
||||
g_value_set_int (value, src->sizemin);
|
||||
break;
|
||||
case PROP_SIZEMAX:
|
||||
g_value_set_int (value, src->sizemax);
|
||||
break;
|
||||
case PROP_PARENTSIZE:
|
||||
g_value_set_int (value, src->parentsize);
|
||||
break;
|
||||
case PROP_FILLTYPE:
|
||||
g_value_set_enum (value, src->filltype);
|
||||
break;
|
||||
case PROP_DATARATE:
|
||||
g_value_set_int (value, src->datarate);
|
||||
break;
|
||||
case PROP_SYNC:
|
||||
g_value_set_boolean (value, src->sync);
|
||||
break;
|
||||
case PROP_PATTERN:
|
||||
g_value_set_string (value, src->pattern);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
g_value_set_boolean (value, src->silent);
|
||||
break;
|
||||
case PROP_SIGNAL_HANDOFFS:
|
||||
g_value_set_boolean (value, src->signal_handoffs);
|
||||
break;
|
||||
case PROP_DUMP:
|
||||
g_value_set_boolean (value, src->dump);
|
||||
break;
|
||||
case PROP_LAST_MESSAGE:
|
||||
GST_OBJECT_LOCK (src);
|
||||
g_value_set_string (value, src->last_message);
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PUSH:
|
||||
g_value_set_boolean (value, GST_BASE_SRC (src)->can_activate_push);
|
||||
break;
|
||||
case PROP_CAN_ACTIVATE_PULL:
|
||||
g_value_set_boolean (value, src->can_activate_pull);
|
||||
break;
|
||||
case PROP_IS_LIVE:
|
||||
g_value_set_boolean (value, gst_base_src_is_live (basesrc));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fake_src_prepare_buffer (GstFakeSrc * src, GstBuffer * buf)
|
||||
{
|
||||
if (GST_BUFFER_SIZE (buf) == 0)
|
||||
return;
|
||||
|
||||
switch (src->filltype) {
|
||||
case FAKE_SRC_FILLTYPE_ZERO:
|
||||
memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
|
||||
break;
|
||||
case FAKE_SRC_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 FAKE_SRC_FILLTYPE_PATTERN:
|
||||
src->pattern_byte = 0x00;
|
||||
case FAKE_SRC_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 FAKE_SRC_FILLTYPE_NOTHING:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_fake_src_alloc_buffer (GstFakeSrc * src, guint size)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
buf = gst_buffer_new ();
|
||||
GST_BUFFER_SIZE (buf) = size;
|
||||
|
||||
if (size != 0) {
|
||||
switch (src->filltype) {
|
||||
case FAKE_SRC_FILLTYPE_NOTHING:
|
||||
GST_BUFFER_DATA (buf) = g_malloc (size);
|
||||
GST_BUFFER_MALLOCDATA (buf) = GST_BUFFER_DATA (buf);
|
||||
break;
|
||||
case FAKE_SRC_FILLTYPE_ZERO:
|
||||
GST_BUFFER_DATA (buf) = g_malloc0 (size);
|
||||
GST_BUFFER_MALLOCDATA (buf) = GST_BUFFER_DATA (buf);
|
||||
break;
|
||||
case FAKE_SRC_FILLTYPE_RANDOM:
|
||||
case FAKE_SRC_FILLTYPE_PATTERN:
|
||||
case FAKE_SRC_FILLTYPE_PATTERN_CONT:
|
||||
default:
|
||||
GST_BUFFER_DATA (buf) = g_malloc (size);
|
||||
GST_BUFFER_MALLOCDATA (buf) = GST_BUFFER_DATA (buf);
|
||||
gst_fake_src_prepare_buffer (src, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static guint
|
||||
gst_fake_src_get_size (GstFakeSrc * src)
|
||||
{
|
||||
guint size;
|
||||
|
||||
switch (src->sizetype) {
|
||||
case FAKE_SRC_SIZETYPE_FIXED:
|
||||
size = src->sizemax;
|
||||
break;
|
||||
case FAKE_SRC_SIZETYPE_RANDOM:
|
||||
size =
|
||||
src->sizemin +
|
||||
(guint8) (((gfloat) src->sizemax) * rand () / (RAND_MAX +
|
||||
(gfloat) src->sizemin));
|
||||
break;
|
||||
case FAKE_SRC_SIZETYPE_EMPTY:
|
||||
default:
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_fake_src_create_buffer (GstFakeSrc * src)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
guint size;
|
||||
gboolean dump = src->dump;
|
||||
|
||||
size = gst_fake_src_get_size (src);
|
||||
if (size == 0)
|
||||
return gst_buffer_new ();
|
||||
|
||||
switch (src->data) {
|
||||
case FAKE_SRC_DATA_ALLOCATE:
|
||||
buf = gst_fake_src_alloc_buffer (src, size);
|
||||
break;
|
||||
case FAKE_SRC_DATA_SUBBUFFER:
|
||||
/* see if we have a parent to subbuffer */
|
||||
if (!src->parent) {
|
||||
gst_fake_src_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_fake_src_create_buffer (src);
|
||||
}
|
||||
gst_fake_src_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 GstFlowReturn
|
||||
gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
|
||||
GstBuffer ** ret)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
GstBuffer *buf;
|
||||
GstClockTime time;
|
||||
|
||||
src = GST_FAKE_SRC (basesrc);
|
||||
|
||||
buf = gst_fake_src_create_buffer (src);
|
||||
GST_BUFFER_OFFSET (buf) = src->buffer_count++;
|
||||
|
||||
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;
|
||||
} else if (gst_base_src_is_live (basesrc)) {
|
||||
GstClock *clock;
|
||||
|
||||
clock = gst_element_get_clock (GST_ELEMENT (src));
|
||||
|
||||
if (clock) {
|
||||
time = gst_clock_get_time (clock);
|
||||
time -= gst_element_get_base_time (GST_ELEMENT (src));
|
||||
gst_object_unref (clock);
|
||||
} else {
|
||||
/* not an error not to have a clock */
|
||||
time = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
} else {
|
||||
time = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) = time;
|
||||
|
||||
if (!src->silent) {
|
||||
gchar ts_str[64], dur_str[64];
|
||||
|
||||
GST_OBJECT_LOCK (src);
|
||||
g_free (src->last_message);
|
||||
|
||||
if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
|
||||
g_snprintf (ts_str, sizeof (ts_str), "%" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||
} else {
|
||||
g_strlcpy (ts_str, "none", sizeof (ts_str));
|
||||
}
|
||||
|
||||
if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) {
|
||||
g_snprintf (dur_str, sizeof (dur_str), "%" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
|
||||
} else {
|
||||
g_strlcpy (dur_str, "none", sizeof (dur_str));
|
||||
}
|
||||
|
||||
src->last_message =
|
||||
g_strdup_printf ("get ******* > (%5d bytes, timestamp: %s"
|
||||
", duration: %s, offset: %" G_GINT64_FORMAT ", offset_end: %"
|
||||
G_GINT64_FORMAT ", flags: %d) %p", GST_BUFFER_SIZE (buf), ts_str,
|
||||
dur_str, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf),
|
||||
GST_MINI_OBJECT (buf)->flags, buf);
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
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_fake_src_signals[SIGNAL_HANDOFF], 0,
|
||||
buf, basesrc->srcpad);
|
||||
GST_LOG_OBJECT (src, "post handoff emit");
|
||||
}
|
||||
|
||||
src->bytes_sent += GST_BUFFER_SIZE (buf);
|
||||
|
||||
*ret = buf;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fake_src_start (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
|
||||
src = GST_FAKE_SRC (basesrc);
|
||||
|
||||
src->buffer_count = 0;
|
||||
src->pattern_byte = 0x00;
|
||||
src->bytes_sent = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fake_src_stop (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstFakeSrc *src;
|
||||
|
||||
src = GST_FAKE_SRC (basesrc);
|
||||
|
||||
GST_OBJECT_LOCK (src);
|
||||
if (src->parent) {
|
||||
gst_buffer_unref (src->parent);
|
||||
src->parent = NULL;
|
||||
}
|
||||
g_free (src->last_message);
|
||||
src->last_message = NULL;
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fake_src_is_seekable (GstBaseSrc * basesrc)
|
||||
{
|
||||
GstFakeSrc *src = GST_FAKE_SRC (basesrc);
|
||||
|
||||
return src->can_activate_pull;
|
||||
}
|
|
@ -1,168 +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_FAKE_SRC_H__
|
||||
#define __GST_FAKE_SRC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesrc.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GstFakeSrcOutputType:
|
||||
* @FAKE_SRC_FIRST_LAST_LOOP: first pad then last pad
|
||||
* @FAKE_SRC_LAST_FIRST_LOOP: last pad then first pad
|
||||
* @FAKE_SRC_PING_PONG: ping pong between pads
|
||||
* @FAKE_SRC_ORDERED_RANDOM: ordered random pad
|
||||
* @FAKE_SRC_RANDOM: random pad
|
||||
* @FAKE_SRC_PATTERN_LOOP: loop between pads in a particular pattern
|
||||
* @FAKE_SRC_PING_PONG_PATTERN: ping pong based on a pattern
|
||||
* @FAKE_SRC_GET_ALWAYS_SUCEEDS: a get always succeeds on a pad
|
||||
*
|
||||
* The different output types. Unused currently.
|
||||
*/
|
||||
typedef enum {
|
||||
FAKE_SRC_FIRST_LAST_LOOP = 1,
|
||||
FAKE_SRC_LAST_FIRST_LOOP,
|
||||
FAKE_SRC_PING_PONG,
|
||||
FAKE_SRC_ORDERED_RANDOM,
|
||||
FAKE_SRC_RANDOM,
|
||||
FAKE_SRC_PATTERN_LOOP,
|
||||
FAKE_SRC_PING_PONG_PATTERN,
|
||||
FAKE_SRC_GET_ALWAYS_SUCEEDS
|
||||
} GstFakeSrcOutputType;
|
||||
|
||||
/**
|
||||
* GstFakeSrcDataType:
|
||||
* @FAKE_SRC_DATA_ALLOCATE: allocate buffers
|
||||
* @FAKE_SRC_DATA_SUBBUFFER: subbuffer each buffer
|
||||
*
|
||||
* The different ways buffers are allocated.
|
||||
*/
|
||||
typedef enum {
|
||||
FAKE_SRC_DATA_ALLOCATE = 1,
|
||||
FAKE_SRC_DATA_SUBBUFFER
|
||||
} GstFakeSrcDataType;
|
||||
|
||||
/**
|
||||
* GstFakeSrcSizeType:
|
||||
* @FAKE_SRC_SIZETYPE_EMPTY: create empty buffers
|
||||
* @FAKE_SRC_SIZETYPE_FIXED: fixed buffer size
|
||||
* @FAKE_SRC_SIZETYPE_RANDOM: random buffer size
|
||||
*
|
||||
* The different size of the allocated buffers.
|
||||
*/
|
||||
typedef enum {
|
||||
FAKE_SRC_SIZETYPE_EMPTY = 1,
|
||||
FAKE_SRC_SIZETYPE_FIXED,
|
||||
FAKE_SRC_SIZETYPE_RANDOM
|
||||
} GstFakeSrcSizeType;
|
||||
|
||||
/**
|
||||
* GstFakeSrcFillType:
|
||||
* @FAKE_SRC_FILLTYPE_NOTHING: do not fill buffers
|
||||
* @FAKE_SRC_FILLTYPE_ZERO: fill buffers with 0
|
||||
* @FAKE_SRC_FILLTYPE_RANDOM: fill buffers with random bytes
|
||||
* @FAKE_SRC_FILLTYPE_PATTERN: fill buffers with a pattern
|
||||
* @FAKE_SRC_FILLTYPE_PATTERN_CONT: fill buffers with a continuous pattern
|
||||
*
|
||||
* The different ways of filling the buffers.
|
||||
*/
|
||||
typedef enum {
|
||||
FAKE_SRC_FILLTYPE_NOTHING = 1,
|
||||
FAKE_SRC_FILLTYPE_ZERO,
|
||||
FAKE_SRC_FILLTYPE_RANDOM,
|
||||
FAKE_SRC_FILLTYPE_PATTERN,
|
||||
FAKE_SRC_FILLTYPE_PATTERN_CONT
|
||||
} GstFakeSrcFillType;
|
||||
|
||||
#define GST_TYPE_FAKE_SRC \
|
||||
(gst_fake_src_get_type())
|
||||
#define GST_FAKE_SRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FAKE_SRC,GstFakeSrc))
|
||||
#define GST_FAKE_SRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FAKE_SRC,GstFakeSrcClass))
|
||||
#define GST_IS_FAKE_SRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FAKE_SRC))
|
||||
#define GST_IS_FAKE_SRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FAKE_SRC))
|
||||
|
||||
typedef struct _GstFakeSrc GstFakeSrc;
|
||||
typedef struct _GstFakeSrcClass GstFakeSrcClass;
|
||||
|
||||
/**
|
||||
* GstFakeSrc:
|
||||
*
|
||||
* Opaque #GstFakeSrc data structure.
|
||||
*/
|
||||
struct _GstFakeSrc {
|
||||
GstBaseSrc element;
|
||||
|
||||
/*< private >*/
|
||||
gboolean has_loop;
|
||||
gboolean has_getrange;
|
||||
|
||||
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;
|
||||
|
||||
gint num_buffers;
|
||||
gint rt_num_buffers; /* we are going to change this at runtime */
|
||||
gint64 buffer_count;
|
||||
gboolean silent;
|
||||
gboolean signal_handoffs;
|
||||
gboolean dump;
|
||||
gboolean can_activate_pull;
|
||||
|
||||
guint64 bytes_sent;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstFakeSrcClass {
|
||||
GstBaseSrcClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
|
||||
};
|
||||
|
||||
GType gst_fake_src_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FAKE_SRC_H__ */
|
|
@ -1,170 +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
|
||||
|
||||
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
|
||||
|
||||
static 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);
|
||||
|
||||
gobject_class->set_property = gst_fdsink_set_property;
|
||||
gobject_class->get_property = gst_fdsink_get_property;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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,494 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Philippe Khalaf <burger@speedy.org>
|
||||
*
|
||||
* 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"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.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"
|
||||
|
||||
/* the select call is also performed on the control sockets, that way
|
||||
* we can send special commands to unblock the select call */
|
||||
#define CONTROL_STOP 'S' /* stop the select call */
|
||||
#define CONTROL_SOCKETS(src) src->control_sock
|
||||
#define WRITE_SOCKET(src) src->control_sock[1]
|
||||
#define READ_SOCKET(src) src->control_sock[0]
|
||||
|
||||
#define SEND_COMMAND(src, command) \
|
||||
G_STMT_START { \
|
||||
unsigned char c; c = command; \
|
||||
write (WRITE_SOCKET(src), &c, 1); \
|
||||
} G_STMT_END
|
||||
|
||||
#define READ_COMMAND(src, command, res) \
|
||||
G_STMT_START { \
|
||||
res = read(READ_SOCKET(src), &command, 1); \
|
||||
} G_STMT_END
|
||||
|
||||
#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
|
||||
|
||||
static GstElementDetails gst_fdsrc_details = GST_ELEMENT_DETAILS ("Disk Source",
|
||||
"Source/File",
|
||||
"Synchronous read from a file",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>");
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_FD,
|
||||
};
|
||||
|
||||
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_PUSH_SRC,
|
||||
_do_init);
|
||||
|
||||
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 void gst_fdsrc_dispose (GObject * obj);
|
||||
|
||||
static gboolean gst_fdsrc_start (GstBaseSrc * bsrc);
|
||||
static gboolean gst_fdsrc_stop (GstBaseSrc * bsrc);
|
||||
static gboolean gst_fdsrc_unlock (GstBaseSrc * bsrc);
|
||||
static gboolean gst_fdsrc_is_seekable (GstBaseSrc * bsrc);
|
||||
static gboolean gst_fdsrc_get_size (GstBaseSrc * src, guint64 * size);
|
||||
|
||||
static GstFlowReturn gst_fdsrc_create (GstPushSrc * psrc, GstBuffer ** outbuf);
|
||||
|
||||
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;
|
||||
GstBaseSrcClass *gstbasesrc_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstPushSrcClass *gstpush_src_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
gstbasesrc_class = (GstBaseSrcClass *) klass;
|
||||
gstpush_src_class = (GstPushSrcClass *) klass;
|
||||
|
||||
parent_class = g_type_class_ref (GST_TYPE_PUSH_SRC);
|
||||
|
||||
gobject_class->set_property = gst_fdsrc_set_property;
|
||||
gobject_class->get_property = gst_fdsrc_get_property;
|
||||
gobject_class->dispose = gst_fdsrc_dispose;
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FD,
|
||||
g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
|
||||
0, G_MAXINT, 0, G_PARAM_READWRITE));
|
||||
|
||||
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_fdsrc_start);
|
||||
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_fdsrc_stop);
|
||||
gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_fdsrc_unlock);
|
||||
gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fdsrc_is_seekable);
|
||||
gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_fdsrc_get_size);
|
||||
|
||||
gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_fdsrc_create);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsrc_init (GstFdSrc * fdsrc, GstFdSrcClass * klass)
|
||||
{
|
||||
fdsrc->fd = 0;
|
||||
fdsrc->new_fd = 0;
|
||||
fdsrc->seekable_fd = FALSE;
|
||||
fdsrc->uri = g_strdup_printf ("fd://%d", fdsrc->fd);
|
||||
fdsrc->curoffset = 0;
|
||||
}
|
||||
|
||||
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_update_fd (GstFdSrc * src)
|
||||
{
|
||||
struct stat stat_results;
|
||||
|
||||
src->fd = src->new_fd;
|
||||
g_free (src->uri);
|
||||
src->uri = g_strdup_printf ("fd://%d", src->fd);
|
||||
|
||||
if (fstat (src->fd, &stat_results) < 0)
|
||||
goto not_seekable;
|
||||
|
||||
if (!S_ISREG (stat_results.st_mode))
|
||||
goto not_seekable;
|
||||
|
||||
/* Try a seek of 0 bytes offset to check for seekability */
|
||||
if (lseek (src->fd, SEEK_CUR, 0) < 0)
|
||||
goto not_seekable;
|
||||
|
||||
src->seekable_fd = TRUE;
|
||||
return;
|
||||
|
||||
not_seekable:
|
||||
src->seekable_fd = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fdsrc_start (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (bsrc);
|
||||
gint control_sock[2];
|
||||
|
||||
src->curoffset = 0;
|
||||
|
||||
gst_fdsrc_update_fd (src);
|
||||
|
||||
if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
|
||||
goto socket_pair;
|
||||
|
||||
READ_SOCKET (src) = control_sock[0];
|
||||
WRITE_SOCKET (src) = control_sock[1];
|
||||
|
||||
fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK);
|
||||
fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
socket_pair:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
|
||||
GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fdsrc_stop (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (bsrc);
|
||||
|
||||
close (READ_SOCKET (src));
|
||||
close (WRITE_SOCKET (src));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_fdsrc_unlock (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (bsrc);
|
||||
|
||||
SEND_COMMAND (src, CONTROL_STOP);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_fdsrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FD:
|
||||
src->new_fd = g_value_get_int (value);
|
||||
|
||||
/* If state is ready or below, update the current fd immediately
|
||||
* so it is reflected in get_properties and uri */
|
||||
GST_OBJECT_LOCK (object);
|
||||
if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
|
||||
gst_fdsrc_update_fd (src);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (object);
|
||||
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 = GST_FDSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FD:
|
||||
g_value_set_int (value, src->fd);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_fdsrc_create (GstPushSrc * psrc, GstBuffer ** outbuf)
|
||||
{
|
||||
GstFdSrc *src;
|
||||
GstBuffer *buf;
|
||||
glong readbytes;
|
||||
guint blocksize;
|
||||
|
||||
#ifndef HAVE_WIN32
|
||||
fd_set readfds;
|
||||
gint retval;
|
||||
#endif
|
||||
|
||||
src = GST_FDSRC (psrc);
|
||||
|
||||
#ifndef HAVE_WIN32
|
||||
FD_ZERO (&readfds);
|
||||
FD_SET (src->fd, &readfds);
|
||||
FD_SET (READ_SOCKET (src), &readfds);
|
||||
|
||||
do {
|
||||
retval = select (FD_SETSIZE, &readfds, NULL, NULL, NULL);
|
||||
} while ((retval == -1 && errno == EINTR));
|
||||
|
||||
if (retval == -1)
|
||||
goto select_error;
|
||||
|
||||
if (FD_ISSET (READ_SOCKET (src), &readfds)) {
|
||||
/* read all stop commands */
|
||||
while (TRUE) {
|
||||
gchar command;
|
||||
int res;
|
||||
|
||||
READ_COMMAND (src, command, res);
|
||||
if (res < 0) {
|
||||
GST_LOG_OBJECT (src, "no more commands");
|
||||
/* no more commands */
|
||||
break;
|
||||
}
|
||||
}
|
||||
goto stopped;
|
||||
}
|
||||
#endif
|
||||
|
||||
blocksize = GST_BASE_SRC (src)->blocksize;
|
||||
|
||||
/* create the buffer */
|
||||
buf = gst_buffer_new_and_alloc (blocksize);
|
||||
|
||||
do {
|
||||
readbytes = read (src->fd, GST_BUFFER_DATA (buf), blocksize);
|
||||
} while (readbytes == -1 && errno == EINTR); /* retry if interrupted */
|
||||
|
||||
if (readbytes < 0)
|
||||
goto read_error;
|
||||
|
||||
if (readbytes == 0)
|
||||
goto eos;
|
||||
|
||||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||
GST_BUFFER_SIZE (buf) = readbytes;
|
||||
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
|
||||
src->curoffset += readbytes;
|
||||
|
||||
GST_DEBUG_OBJECT (psrc, "Read buffer of size %u.", readbytes);
|
||||
|
||||
/* we're done, return the buffer */
|
||||
*outbuf = buf;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* ERRORS */
|
||||
#ifndef HAVE_WIN32
|
||||
select_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
||||
("select on file descriptor: %s.", g_strerror (errno)));
|
||||
GST_DEBUG_OBJECT (psrc, "Error during select");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
stopped:
|
||||
{
|
||||
GST_DEBUG_OBJECT (psrc, "Select stopped");
|
||||
return GST_FLOW_WRONG_STATE;
|
||||
}
|
||||
#endif
|
||||
eos:
|
||||
{
|
||||
GST_DEBUG_OBJECT (psrc, "Read 0 bytes. EOS.");
|
||||
gst_buffer_unref (buf);
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
read_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
||||
("read on file descriptor: %s.", g_strerror (errno)));
|
||||
GST_DEBUG_OBJECT (psrc, "Error reading from fd");
|
||||
gst_buffer_unref (buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_fdsrc_is_seekable (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (bsrc);
|
||||
|
||||
return src->seekable_fd;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_fdsrc_get_size (GstBaseSrc * bsrc, guint64 * size)
|
||||
{
|
||||
GstFdSrc *src = GST_FDSRC (bsrc);
|
||||
struct stat stat_results;
|
||||
|
||||
if (!src->seekable_fd) {
|
||||
/* If it isn't seekable, we won't know the length (but fstat will still
|
||||
* succeed, and wrongly say our length is zero. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (fstat (src->fd, &stat_results) < 0)
|
||||
goto could_not_stat;
|
||||
|
||||
*size = stat_results.st_size;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERROR */
|
||||
could_not_stat:
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*** 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;
|
||||
|
||||
protocol = gst_uri_get_protocol (uri);
|
||||
if (strcmp (protocol, "fd") != 0) {
|
||||
g_free (protocol);
|
||||
return FALSE;
|
||||
}
|
||||
g_free (protocol);
|
||||
|
||||
if (sscanf (uri, "fd://%d", &fd) != 1)
|
||||
return FALSE;
|
||||
|
||||
src->new_fd = fd;
|
||||
|
||||
GST_OBJECT_LOCK (src);
|
||||
if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
|
||||
gst_fdsrc_update_fd (src);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
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,77 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Philippe Khalaf <burger@speedy.org>
|
||||
*
|
||||
* 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>
|
||||
#include <gst/base/gstpushsrc.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 {
|
||||
GstPushSrc element;
|
||||
|
||||
/* new_fd is copied to fd on READY->PAUSED */
|
||||
gint new_fd;
|
||||
|
||||
/* fd and flag indicating whether fd is seekable */
|
||||
gint fd;
|
||||
gboolean seekable_fd;
|
||||
|
||||
gchar *uri;
|
||||
|
||||
gint control_sock[2];
|
||||
|
||||
gulong curoffset; /* current offset in file */
|
||||
};
|
||||
|
||||
struct _GstFdSrcClass {
|
||||
GstPushSrcClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*timeout) (GstElement *element);
|
||||
};
|
||||
|
||||
GType gst_fdsrc_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FDSRC_H__ */
|
|
@ -1,495 +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.
|
||||
*/
|
||||
/**
|
||||
* SECTION:gstfilesink
|
||||
* @short_description: write stream to a file
|
||||
* @see_also: #GstFileSrc
|
||||
*
|
||||
* Write incoming data to a file in the local file system.
|
||||
*/
|
||||
|
||||
#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_file_sink_debug);
|
||||
#define GST_CAT_DEFAULT gst_file_sink_debug
|
||||
|
||||
static GstElementDetails gst_file_sink_details =
|
||||
GST_ELEMENT_DETAILS ("File Sink",
|
||||
"Sink/File",
|
||||
"Write stream to a file",
|
||||
"Thomas <thomas@apestaart.org>");
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_LOCATION
|
||||
};
|
||||
|
||||
static void gst_file_sink_dispose (GObject * object);
|
||||
|
||||
static void gst_file_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_file_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static gboolean gst_file_sink_open_file (GstFileSink * sink);
|
||||
static void gst_file_sink_close_file (GstFileSink * sink);
|
||||
|
||||
static gboolean gst_file_sink_start (GstBaseSink * sink);
|
||||
static gboolean gst_file_sink_stop (GstBaseSink * sink);
|
||||
static gboolean gst_file_sink_event (GstBaseSink * sink, GstEvent * event);
|
||||
static GstFlowReturn gst_file_sink_render (GstBaseSink * sink,
|
||||
GstBuffer * buffer);
|
||||
|
||||
static gboolean gst_file_sink_query (GstPad * pad, GstQuery * query);
|
||||
|
||||
static void gst_file_sink_uri_handler_init (gpointer g_iface,
|
||||
gpointer iface_data);
|
||||
|
||||
|
||||
static void
|
||||
_do_init (GType filesink_type)
|
||||
{
|
||||
static const GInterfaceInfo urihandler_info = {
|
||||
gst_file_sink_uri_handler_init,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
g_type_add_interface_static (filesink_type, GST_TYPE_URI_HANDLER,
|
||||
&urihandler_info);
|
||||
GST_DEBUG_CATEGORY_INIT (gst_file_sink_debug, "filesink", 0,
|
||||
"filesink element");
|
||||
}
|
||||
|
||||
GST_BOILERPLATE_FULL (GstFileSink, gst_file_sink, GstBaseSink,
|
||||
GST_TYPE_BASE_SINK, _do_init);
|
||||
|
||||
static void
|
||||
gst_file_sink_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_file_sink_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_file_sink_class_init (GstFileSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gst_file_sink_set_property;
|
||||
gobject_class->get_property = gst_file_sink_get_property;
|
||||
|
||||
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));
|
||||
|
||||
gobject_class->dispose = gst_file_sink_dispose;
|
||||
|
||||
gstbasesink_class->get_times = NULL;
|
||||
gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_file_sink_start);
|
||||
gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_file_sink_stop);
|
||||
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_file_sink_render);
|
||||
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_file_sink_event);
|
||||
|
||||
if (sizeof (off_t) < 8) {
|
||||
GST_LOG ("No large file support, sizeof (off_t) = %u", sizeof (off_t));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_file_sink_init (GstFileSink * filesink, GstFileSinkClass * g_class)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad = GST_BASE_SINK_PAD (filesink);
|
||||
|
||||
gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_file_sink_query));
|
||||
|
||||
filesink->filename = NULL;
|
||||
filesink->file = NULL;
|
||||
|
||||
GST_BASE_SINK (filesink)->sync = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_file_sink_dispose (GObject * object)
|
||||
{
|
||||
GstFileSink *sink = GST_FILE_SINK (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_file_sink_set_location (GstFileSink * sink, const gchar * location)
|
||||
{
|
||||
if (sink->file) {
|
||||
g_warning ("Changing the `location' property on filesink when "
|
||||
"a file is open not supported.");
|
||||
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;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
static void
|
||||
gst_file_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstFileSink *sink = GST_FILE_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_LOCATION:
|
||||
gst_file_sink_set_location (sink, g_value_get_string (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_file_sink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstFileSink *sink = GST_FILE_SINK (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_file_sink_open_file (GstFileSink * sink)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
sink->data_written = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_file_sink_close_file (GstFileSink * sink)
|
||||
{
|
||||
if (sink->file) {
|
||||
if (fclose (sink->file) != 0) {
|
||||
GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
|
||||
(_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_file_sink_query (GstPad * pad, GstQuery * query)
|
||||
{
|
||||
GstFileSink *self;
|
||||
GstFormat format;
|
||||
|
||||
self = GST_FILE_SINK (GST_PAD_PARENT (pad));
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_POSITION:
|
||||
gst_query_parse_position (query, &format, NULL);
|
||||
switch (format) {
|
||||
case GST_FORMAT_DEFAULT:
|
||||
case GST_FORMAT_BYTES:
|
||||
gst_query_set_position (query, GST_FORMAT_BYTES, self->data_written);
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
case GST_QUERY_FORMATS:
|
||||
gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES);
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return gst_pad_query_default (pad, query);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_FSEEKO
|
||||
# define __GST_STDIO_SEEK_FUNCTION "fseeko"
|
||||
#elif G_OS_UNIX
|
||||
# define __GST_STDIO_SEEK_FUNCTION "lseek"
|
||||
#else
|
||||
# define __GST_STDIO_SEEK_FUNCTION "fseek"
|
||||
#endif
|
||||
|
||||
static void
|
||||
gst_file_sink_do_seek (GstFileSink * filesink, guint64 new_offset)
|
||||
{
|
||||
GST_DEBUG_OBJECT (filesink, "Seeking to offset %" G_GUINT64_FORMAT
|
||||
" using " __GST_STDIO_SEEK_FUNCTION, new_offset);
|
||||
|
||||
if (fflush (filesink->file))
|
||||
goto flush_failed;
|
||||
|
||||
#if HAVE_FSEEKO
|
||||
if (fseeko (filesink->file, (off_t) new_offset, SEEK_SET) != 0)
|
||||
goto seek_failed;
|
||||
#elif G_OS_UNIX
|
||||
if (lseek (fileno (filesink->file), (off_t) new_offset,
|
||||
SEEK_SET) == (off_t) - 1)
|
||||
goto seek_failed;
|
||||
#else
|
||||
if (fseek (filesink->file, (long) new_offset, SEEK_SET) != 0)
|
||||
goto seek_failed;
|
||||
#endif
|
||||
|
||||
return;
|
||||
|
||||
/* ERRORS */
|
||||
flush_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (filesink, "Flush failed: %s", g_strerror (errno));
|
||||
return;
|
||||
}
|
||||
seek_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (filesink, "Seeking failed: %s", g_strerror (errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle events (search) */
|
||||
static gboolean
|
||||
gst_file_sink_event (GstBaseSink * sink, GstEvent * event)
|
||||
{
|
||||
GstEventType type;
|
||||
GstFileSink *filesink;
|
||||
|
||||
filesink = GST_FILE_SINK (sink);
|
||||
|
||||
type = GST_EVENT_TYPE (event);
|
||||
|
||||
switch (type) {
|
||||
case GST_EVENT_NEWSEGMENT:
|
||||
{
|
||||
gint64 soffset, eoffset;
|
||||
GstFormat format;
|
||||
|
||||
gst_event_parse_new_segment (event, NULL, NULL, &format, &soffset,
|
||||
&eoffset, NULL);
|
||||
|
||||
if (format == GST_FORMAT_BYTES) {
|
||||
gst_file_sink_do_seek (filesink, (guint64) soffset);
|
||||
} else {
|
||||
GST_DEBUG ("Ignored NEWSEGMENT event of format %u", (guint) format);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_EOS:
|
||||
if (fflush (filesink->file)) {
|
||||
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
|
||||
(_("Error while writing to file \"%s\"."), filesink->filename),
|
||||
GST_ERROR_SYSTEM);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_file_sink_get_current_offset (GstFileSink * filesink, guint64 * p_pos)
|
||||
{
|
||||
off_t ret;
|
||||
|
||||
#if HAVE_FTELLO
|
||||
ret = ftello (filesink->file);
|
||||
#elif G_OS_UNIX
|
||||
if (fflush (filesink->file)) {
|
||||
GST_DEBUG_OBJECT (filesink, "Flush failed: %s", g_strerror (errno));
|
||||
/* ignore and continue */
|
||||
}
|
||||
ret = lseek (fileno (filesink->file), 0, SEEK_CUR);
|
||||
#else
|
||||
ret = (off_t) ftell (filesink->file);
|
||||
#endif
|
||||
|
||||
*p_pos = (guint64) ret;
|
||||
|
||||
return (ret != (off_t) - 1);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_file_sink_render (GstBaseSink * sink, GstBuffer * buffer)
|
||||
{
|
||||
GstFileSink *filesink;
|
||||
guint64 cur_pos;
|
||||
guint size;
|
||||
guint64 back_pending = 0;
|
||||
|
||||
size = GST_BUFFER_SIZE (buffer);
|
||||
|
||||
filesink = GST_FILE_SINK (sink);
|
||||
|
||||
if (!gst_file_sink_get_current_offset (filesink, &cur_pos))
|
||||
goto handle_error;
|
||||
|
||||
if (cur_pos < filesink->data_written)
|
||||
back_pending = filesink->data_written - cur_pos;
|
||||
|
||||
GST_DEBUG_OBJECT (filesink, "writing %u bytes at %" G_GUINT64_FORMAT,
|
||||
size, cur_pos);
|
||||
|
||||
if (fwrite (GST_BUFFER_DATA (buffer), size, 1, filesink->file) != 1)
|
||||
goto handle_error;
|
||||
|
||||
filesink->data_written += size - back_pending;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
||||
handle_error:
|
||||
|
||||
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
|
||||
(_("Error while writing to file \"%s\"."), filesink->filename),
|
||||
("%s", g_strerror (errno)));
|
||||
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_file_sink_start (GstBaseSink * basesink)
|
||||
{
|
||||
return gst_file_sink_open_file (GST_FILE_SINK (basesink));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_file_sink_stop (GstBaseSink * basesink)
|
||||
{
|
||||
gst_file_sink_close_file (GST_FILE_SINK (basesink));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*** GSTURIHANDLER INTERFACE *************************************************/
|
||||
|
||||
static guint
|
||||
gst_file_sink_uri_get_type (void)
|
||||
{
|
||||
return GST_URI_SINK;
|
||||
}
|
||||
static gchar **
|
||||
gst_file_sink_uri_get_protocols (void)
|
||||
{
|
||||
static gchar *protocols[] = { "file", NULL };
|
||||
|
||||
return protocols;
|
||||
}
|
||||
static const gchar *
|
||||
gst_file_sink_uri_get_uri (GstURIHandler * handler)
|
||||
{
|
||||
GstFileSink *sink = GST_FILE_SINK (handler);
|
||||
|
||||
return sink->uri;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_file_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
|
||||
{
|
||||
gchar *protocol, *location;
|
||||
gboolean ret;
|
||||
GstFileSink *sink = GST_FILE_SINK (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_file_sink_set_location (sink, location);
|
||||
g_free (location);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_file_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
|
||||
{
|
||||
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
|
||||
|
||||
iface->get_type = gst_file_sink_uri_get_type;
|
||||
iface->get_protocols = gst_file_sink_uri_get_protocols;
|
||||
iface->get_uri = gst_file_sink_uri_get_uri;
|
||||
iface->set_uri = gst_file_sink_uri_set_uri;
|
||||
}
|
|
@ -1,70 +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_FILE_SINK_H__
|
||||
#define __GST_FILE_SINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_FILE_SINK \
|
||||
(gst_file_sink_get_type())
|
||||
#define GST_FILE_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FILE_SINK,GstFileSink))
|
||||
#define GST_FILE_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FILE_SINK,GstFileSinkClass))
|
||||
#define GST_IS_FILE_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FILE_SINK))
|
||||
#define GST_IS_FILE_SINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILE_SINK))
|
||||
|
||||
typedef struct _GstFileSink GstFileSink;
|
||||
typedef struct _GstFileSinkClass GstFileSinkClass;
|
||||
|
||||
/**
|
||||
* GstFileSink:
|
||||
*
|
||||
* Opaque #GstFileSink structure.
|
||||
*/
|
||||
struct _GstFileSink {
|
||||
GstBaseSink parent;
|
||||
|
||||
/*< private >*/
|
||||
gchar *filename;
|
||||
gchar *uri;
|
||||
FILE *file;
|
||||
|
||||
guint64 data_written;
|
||||
};
|
||||
|
||||
struct _GstFileSinkClass {
|
||||
GstBaseSinkClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_file_sink_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FILE_SINK_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,81 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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_FILE_SRC_H__
|
||||
#define __GST_FILE_SRC_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesrc.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_FILE_SRC \
|
||||
(gst_file_src_get_type())
|
||||
#define GST_FILE_SRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FILE_SRC,GstFileSrc))
|
||||
#define GST_FILE_SRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FILE_SRC,GstFileSrcClass))
|
||||
#define GST_IS_FILE_SRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FILE_SRC))
|
||||
#define GST_IS_FILE_SRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILE_SRC))
|
||||
|
||||
typedef struct _GstFileSrc GstFileSrc;
|
||||
typedef struct _GstFileSrcClass GstFileSrcClass;
|
||||
|
||||
/**
|
||||
* GstFileSrc:
|
||||
*
|
||||
* Opaque #GstFileSrc structure.
|
||||
*/
|
||||
struct _GstFileSrc {
|
||||
GstBaseSrc element;
|
||||
|
||||
/*< private >*/
|
||||
guint pagesize; /* system page size */
|
||||
|
||||
gchar *filename; /* filename */
|
||||
gchar *uri; /* caching the URI */
|
||||
gint fd; /* open file descriptor */
|
||||
guint64 read_position; /* position of fd */
|
||||
|
||||
gboolean touch; /* whether to touch every page */
|
||||
gboolean using_mmap; /* whether we opened it with mmap */
|
||||
gboolean seekable; /* whether the file is seekable */
|
||||
gboolean is_regular; /* whether it's a (symlink to a)
|
||||
regular file */
|
||||
GstBuffer *mapbuf;
|
||||
size_t mapsize;
|
||||
};
|
||||
|
||||
struct _GstFileSrcClass {
|
||||
GstBaseSrcClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_file_src_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_FILE_SRC_H__ */
|
|
@ -1,567 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
static 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_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_SINGLE_SEGMENT FALSE
|
||||
#define DEFAULT_DUMP FALSE
|
||||
#define DEFAULT_SYNC FALSE
|
||||
#define DEFAULT_CHECK_PERFECT FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SLEEP_TIME,
|
||||
PROP_ERROR_AFTER,
|
||||
PROP_DROP_PROBABILITY,
|
||||
PROP_DATARATE,
|
||||
PROP_SILENT,
|
||||
PROP_SINGLE_SEGMENT,
|
||||
PROP_LAST_MESSAGE,
|
||||
PROP_DUMP,
|
||||
PROP_SYNC,
|
||||
PROP_CHECK_PERFECT
|
||||
};
|
||||
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstBaseTransform,
|
||||
GST_TYPE_BASE_TRANSFORM, _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 gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event);
|
||||
static GstFlowReturn gst_identity_transform_ip (GstBaseTransform * trans,
|
||||
GstBuffer * buf);
|
||||
static gboolean gst_identity_start (GstBaseTransform * trans);
|
||||
static gboolean gst_identity_stop (GstBaseTransform * trans);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* fixme: do something about this */
|
||||
static void
|
||||
marshal_VOID__MINIOBJECT (GClosure * closure, GValue * return_value,
|
||||
guint n_param_values, const GValue * param_values, gpointer invocation_hint,
|
||||
gpointer marshal_data)
|
||||
{
|
||||
typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1,
|
||||
gpointer data2);
|
||||
register marshalfunc_VOID__MINIOBJECT callback;
|
||||
register GCClosure *cc = (GCClosure *) closure;
|
||||
register gpointer data1, data2;
|
||||
|
||||
g_return_if_fail (n_param_values == 2);
|
||||
|
||||
if (G_CCLOSURE_SWAP_DATA (closure)) {
|
||||
data1 = closure->data;
|
||||
data2 = g_value_peek_pointer (param_values + 0);
|
||||
} else {
|
||||
data1 = g_value_peek_pointer (param_values + 0);
|
||||
data2 = closure->data;
|
||||
}
|
||||
callback =
|
||||
(marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : cc->
|
||||
callback);
|
||||
|
||||
callback (data1, gst_value_get_mini_object (param_values + 1), data2);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_class_init (GstIdentityClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseTransformClass *gstbasetrans_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_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), PROP_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),
|
||||
PROP_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), PROP_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), PROP_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent", DEFAULT_SILENT,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SINGLE_SEGMENT,
|
||||
g_param_spec_boolean ("single-segment", "Single Segment",
|
||||
"Timestamp buffers and eat newsegments so as to appear as one segment",
|
||||
DEFAULT_SINGLE_SEGMENT, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_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), PROP_DUMP,
|
||||
g_param_spec_boolean ("dump", "Dump", "Dump buffer contents",
|
||||
DEFAULT_DUMP, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_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), PROP_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,
|
||||
marshal_VOID__MINIOBJECT, G_TYPE_NONE, 1, GST_TYPE_BUFFER);
|
||||
|
||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
|
||||
|
||||
gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_identity_event);
|
||||
gstbasetrans_class->transform_ip =
|
||||
GST_DEBUG_FUNCPTR (gst_identity_transform_ip);
|
||||
gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_identity_start);
|
||||
gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_identity_stop);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_init (GstIdentity * identity, GstIdentityClass * g_class)
|
||||
{
|
||||
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (identity), TRUE);
|
||||
|
||||
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
||||
identity->error_after = DEFAULT_ERROR_AFTER;
|
||||
identity->drop_probability = DEFAULT_DROP_PROBABILITY;
|
||||
identity->datarate = DEFAULT_DATARATE;
|
||||
identity->silent = DEFAULT_SILENT;
|
||||
identity->single_segment = DEFAULT_SINGLE_SEGMENT;
|
||||
identity->sync = DEFAULT_SYNC;
|
||||
identity->check_perfect = DEFAULT_CHECK_PERFECT;
|
||||
identity->dump = DEFAULT_DUMP;
|
||||
identity->last_message = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_identity_event (GstBaseTransform * trans, GstEvent * event)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
identity = GST_IDENTITY (trans);
|
||||
|
||||
if (!identity->silent) {
|
||||
const GstStructure *s;
|
||||
gchar *sstr;
|
||||
|
||||
GST_OBJECT_LOCK (identity);
|
||||
g_free (identity->last_message);
|
||||
|
||||
if ((s = gst_event_get_structure (event)))
|
||||
sstr = gst_structure_to_string (s);
|
||||
else
|
||||
sstr = g_strdup ("");
|
||||
|
||||
identity->last_message =
|
||||
g_strdup_printf ("event ******* (%s:%s) E (type: %d, %s) %p",
|
||||
GST_DEBUG_PAD_NAME (trans->sinkpad), GST_EVENT_TYPE (event), sstr,
|
||||
event);
|
||||
g_free (sstr);
|
||||
GST_OBJECT_UNLOCK (identity);
|
||||
|
||||
g_object_notify (G_OBJECT (identity), "last_message");
|
||||
}
|
||||
|
||||
if (identity->single_segment
|
||||
&& (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)) {
|
||||
if (trans->have_newsegment == FALSE) {
|
||||
GstEvent *news;
|
||||
GstFormat format;
|
||||
|
||||
gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL,
|
||||
NULL);
|
||||
|
||||
/* This is the first newsegment, send out a (0, -1) newsegment */
|
||||
news = gst_event_new_new_segment (TRUE, 1.0, format, 0, -1, 0);
|
||||
|
||||
if (!(gst_pad_event_default (trans->sinkpad, news)))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
GST_BASE_TRANSFORM_CLASS (parent_class)->event (trans, event);
|
||||
|
||||
if (identity->single_segment
|
||||
&& (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)) {
|
||||
/* eat up segments */
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
|
||||
{
|
||||
GstClockTime timestamp;
|
||||
|
||||
timestamp = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
/* see if we need to do perfect stream checking */
|
||||
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
|
||||
if (timestamp != GST_CLOCK_TIME_NONE) {
|
||||
/* check if we had a previous buffer to compare to */
|
||||
if (identity->prev_timestamp != GST_CLOCK_TIME_NONE) {
|
||||
guint64 offset;
|
||||
|
||||
if (identity->prev_timestamp + identity->prev_duration != timestamp) {
|
||||
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 (timestamp));
|
||||
}
|
||||
|
||||
offset = GST_BUFFER_OFFSET (buf);
|
||||
if (identity->prev_offset_end != offset) {
|
||||
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, offset);
|
||||
}
|
||||
}
|
||||
/* update prev values */
|
||||
identity->prev_timestamp = timestamp;
|
||||
identity->prev_duration = GST_BUFFER_DURATION (buf);
|
||||
identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf);
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstIdentity *identity = GST_IDENTITY (trans);
|
||||
GstClockTime runtimestamp = 0LL;
|
||||
|
||||
if (identity->check_perfect)
|
||||
gst_identity_check_perfect (identity, buf);
|
||||
|
||||
if (identity->error_after >= 0) {
|
||||
identity->error_after--;
|
||||
if (identity->error_after == 0) {
|
||||
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
||||
(_("Failed after iterations as requested.")), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (identity->drop_probability > 0.0) {
|
||||
if ((gfloat) (1.0 * rand () / (RAND_MAX)) < identity->drop_probability) {
|
||||
GST_OBJECT_LOCK (identity);
|
||||
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 (trans->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);
|
||||
GST_OBJECT_UNLOCK (identity);
|
||||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (identity->dump) {
|
||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
if (!identity->silent) {
|
||||
GST_OBJECT_LOCK (identity);
|
||||
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 (trans->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);
|
||||
GST_OBJECT_UNLOCK (identity);
|
||||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
}
|
||||
|
||||
if (identity->datarate > 0) {
|
||||
GstClockTime time = identity->offset * 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 (trans->segment.format == GST_FORMAT_TIME)
|
||||
runtimestamp = gst_segment_to_running_time (&trans->segment,
|
||||
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));
|
||||
|
||||
if ((identity->sync) && (trans->segment.format == GST_FORMAT_TIME)) {
|
||||
GstClock *clock;
|
||||
|
||||
GST_OBJECT_LOCK (identity);
|
||||
if ((clock = GST_ELEMENT (identity)->clock)) {
|
||||
GstClockReturn cret;
|
||||
GstClockTime timestamp;
|
||||
|
||||
timestamp = runtimestamp + GST_ELEMENT (identity)->base_time;
|
||||
|
||||
/* save id if we need to unlock */
|
||||
/* FIXME: actually unlock this somewhere in the state changes */
|
||||
identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp);
|
||||
GST_OBJECT_UNLOCK (identity);
|
||||
|
||||
cret = gst_clock_id_wait (identity->clock_id, NULL);
|
||||
|
||||
GST_OBJECT_LOCK (identity);
|
||||
if (identity->clock_id) {
|
||||
gst_clock_id_unref (identity->clock_id);
|
||||
identity->clock_id = NULL;
|
||||
}
|
||||
if (cret == GST_CLOCK_UNSCHEDULED)
|
||||
ret = GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (identity);
|
||||
}
|
||||
|
||||
identity->offset += GST_BUFFER_SIZE (buf);
|
||||
|
||||
if (identity->sleep_time && ret == GST_FLOW_OK)
|
||||
g_usleep (identity->sleep_time);
|
||||
|
||||
if (identity->single_segment && (trans->segment.format == GST_FORMAT_TIME)
|
||||
&& (ret == GST_FLOW_OK))
|
||||
GST_BUFFER_TIMESTAMP (buf) = runtimestamp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_identity_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
|
||||
identity = GST_IDENTITY (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SLEEP_TIME:
|
||||
identity->sleep_time = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
identity->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_SINGLE_SEGMENT:
|
||||
identity->single_segment = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_DUMP:
|
||||
identity->dump = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_ERROR_AFTER:
|
||||
identity->error_after = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_DROP_PROBABILITY:
|
||||
identity->drop_probability = g_value_get_float (value);
|
||||
break;
|
||||
case PROP_DATARATE:
|
||||
identity->datarate = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_SYNC:
|
||||
identity->sync = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_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;
|
||||
|
||||
identity = GST_IDENTITY (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SLEEP_TIME:
|
||||
g_value_set_uint (value, identity->sleep_time);
|
||||
break;
|
||||
case PROP_ERROR_AFTER:
|
||||
g_value_set_int (value, identity->error_after);
|
||||
break;
|
||||
case PROP_DROP_PROBABILITY:
|
||||
g_value_set_float (value, identity->drop_probability);
|
||||
break;
|
||||
case PROP_DATARATE:
|
||||
g_value_set_int (value, identity->datarate);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
g_value_set_boolean (value, identity->silent);
|
||||
break;
|
||||
case PROP_SINGLE_SEGMENT:
|
||||
g_value_set_boolean (value, identity->single_segment);
|
||||
break;
|
||||
case PROP_DUMP:
|
||||
g_value_set_boolean (value, identity->dump);
|
||||
break;
|
||||
case PROP_LAST_MESSAGE:
|
||||
GST_OBJECT_LOCK (identity);
|
||||
g_value_set_string (value, identity->last_message);
|
||||
GST_OBJECT_UNLOCK (identity);
|
||||
break;
|
||||
case PROP_SYNC:
|
||||
g_value_set_boolean (value, identity->sync);
|
||||
break;
|
||||
case PROP_CHECK_PERFECT:
|
||||
g_value_set_boolean (value, identity->check_perfect);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_identity_start (GstBaseTransform * trans)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
|
||||
identity = GST_IDENTITY (trans);
|
||||
|
||||
identity->offset = 0;
|
||||
identity->prev_timestamp = GST_CLOCK_TIME_NONE;
|
||||
identity->prev_duration = GST_CLOCK_TIME_NONE;
|
||||
identity->prev_offset_end = -1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_identity_stop (GstBaseTransform * trans)
|
||||
{
|
||||
GstIdentity *identity;
|
||||
|
||||
identity = GST_IDENTITY (trans);
|
||||
|
||||
GST_OBJECT_LOCK (identity);
|
||||
g_free (identity->last_message);
|
||||
identity->last_message = NULL;
|
||||
GST_OBJECT_UNLOCK (identity);
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -1,79 +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>
|
||||
#include <gst/base/gstbasetransform.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 {
|
||||
GstBaseTransform element;
|
||||
|
||||
GstClockID clock_id;
|
||||
gint error_after;
|
||||
gfloat drop_probability;
|
||||
gint datarate;
|
||||
guint sleep_time;
|
||||
gboolean silent;
|
||||
gboolean dump;
|
||||
gboolean sync;
|
||||
gboolean check_perfect;
|
||||
gboolean single_segment;
|
||||
GstClockTime prev_timestamp;
|
||||
GstClockTime prev_duration;
|
||||
guint64 prev_offset_end;
|
||||
gchar *last_message;
|
||||
guint64 offset;
|
||||
};
|
||||
|
||||
struct _GstIdentityClass {
|
||||
GstBaseTransformClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*handoff) (GstElement *element, GstBuffer *buf);
|
||||
};
|
||||
|
||||
GType gst_identity_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_IDENTITY_H__ */
|
|
@ -1,379 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000,2001,2002,2003,2004,2005 Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
*
|
||||
* 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
|
||||
|
||||
static GstElementDetails gst_tee_details =
|
||||
GST_ELEMENT_DETAILS ("Tee pipe fitting",
|
||||
"Generic",
|
||||
"1-to-N pipe fitting",
|
||||
"Erik Walthinsen <omega@cse.ogi.edu>, "
|
||||
"Wim \"Tim\" Taymans <wim@fluendo.com>");
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_NUM_SRC_PADS,
|
||||
PROP_HAS_SINK_LOOP,
|
||||
PROP_HAS_CHAIN,
|
||||
PROP_SILENT,
|
||||
PROP_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 GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static void gst_tee_loop (GstPad * pad);
|
||||
static gboolean gst_tee_sink_activate_push (GstPad * pad, gboolean active);
|
||||
static gboolean gst_tee_sink_activate_pull (GstPad * pad, gboolean active);
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_SRC_PADS,
|
||||
g_param_spec_int ("num-src-pads", "num-src-pads", "num-src-pads",
|
||||
0, G_MAXINT, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
|
||||
g_param_spec_boolean ("has-sink-loop", "has-sink-loop", "has-sink-loop",
|
||||
FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
|
||||
g_param_spec_boolean ("has-chain", "has-chain", "has-chain",
|
||||
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
|
||||
g_param_spec_boolean ("silent", "silent", "silent",
|
||||
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
|
||||
g_param_spec_string ("last_message", "last_message", "last_message",
|
||||
NULL, G_PARAM_READABLE));
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_tee_request_new_pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_init (GstTee * tee, GstTeeClass * g_class)
|
||||
{
|
||||
tee->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
|
||||
gst_pad_set_setcaps_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
|
||||
gst_pad_set_getcaps_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
|
||||
|
||||
tee->last_message = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_update_pad_functions (GstTee * tee)
|
||||
{
|
||||
gst_pad_set_activatepush_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_tee_sink_activate_push));
|
||||
gst_pad_set_activatepull_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_tee_sink_activate_pull));
|
||||
|
||||
if (tee->has_chain)
|
||||
gst_pad_set_chain_function (tee->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_tee_chain));
|
||||
else
|
||||
gst_pad_set_chain_function (tee->sinkpad, NULL);
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * unused)
|
||||
{
|
||||
gchar *name;
|
||||
GstPad *srcpad;
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (element);
|
||||
|
||||
GST_OBJECT_LOCK (tee);
|
||||
name = g_strdup_printf ("src%d", tee->pad_counter++);
|
||||
GST_OBJECT_UNLOCK (tee);
|
||||
|
||||
srcpad = gst_pad_new_from_template (templ, name);
|
||||
g_free (name);
|
||||
|
||||
gst_pad_set_setcaps_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
|
||||
gst_pad_set_getcaps_function (srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
|
||||
|
||||
return srcpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee = GST_TEE (object);
|
||||
|
||||
GST_OBJECT_LOCK (tee);
|
||||
switch (prop_id) {
|
||||
case PROP_HAS_SINK_LOOP:
|
||||
tee->has_sink_loop = g_value_get_boolean (value);
|
||||
gst_tee_update_pad_functions (tee);
|
||||
break;
|
||||
case PROP_HAS_CHAIN:
|
||||
tee->has_chain = g_value_get_boolean (value);
|
||||
gst_tee_update_pad_functions (tee);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
tee->silent = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (tee);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstTee *tee = GST_TEE (object);
|
||||
|
||||
GST_OBJECT_LOCK (tee);
|
||||
switch (prop_id) {
|
||||
case PROP_NUM_SRC_PADS:
|
||||
g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
|
||||
break;
|
||||
case PROP_HAS_SINK_LOOP:
|
||||
g_value_set_boolean (value, tee->has_sink_loop);
|
||||
break;
|
||||
case PROP_HAS_CHAIN:
|
||||
g_value_set_boolean (value, tee->has_chain);
|
||||
break;
|
||||
case PROP_SILENT:
|
||||
g_value_set_boolean (value, tee->silent);
|
||||
break;
|
||||
case PROP_LAST_MESSAGE:
|
||||
g_value_set_string (value, tee->last_message);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (tee);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstTee *tee;
|
||||
GstBuffer *buffer;
|
||||
} PushData;
|
||||
|
||||
static gboolean
|
||||
gst_tee_do_push (GstPad * pad, GValue * ret, PushData * data)
|
||||
{
|
||||
GstFlowReturn res;
|
||||
|
||||
if (G_UNLIKELY (!data->tee->silent)) {
|
||||
GstTee *tee = data->tee;
|
||||
GstBuffer *buf = data->buffer;
|
||||
|
||||
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 (pad),
|
||||
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
|
||||
g_object_notify (G_OBJECT (tee), "last_message");
|
||||
}
|
||||
|
||||
res = gst_pad_push (pad, gst_buffer_ref (data->buffer));
|
||||
g_value_set_enum (ret, res);
|
||||
|
||||
gst_object_unref (pad);
|
||||
|
||||
return (res == GST_FLOW_OK);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_tee_handle_buffer (GstTee * tee, GstBuffer * buffer)
|
||||
{
|
||||
GstIterator *iter;
|
||||
PushData data;
|
||||
GValue ret = { 0, };
|
||||
GstIteratorResult res;
|
||||
|
||||
tee->offset += GST_BUFFER_SIZE (buffer);
|
||||
|
||||
g_value_init (&ret, GST_TYPE_FLOW_RETURN);
|
||||
iter = gst_element_iterate_src_pads (GST_ELEMENT (tee));
|
||||
data.tee = tee;
|
||||
data.buffer = buffer;
|
||||
|
||||
res = gst_iterator_fold (iter, (GstIteratorFoldFunction) gst_tee_do_push,
|
||||
&ret, &data);
|
||||
gst_iterator_free (iter);
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* no need to unset gvalue */
|
||||
return g_value_get_enum (&ret);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_tee_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstFlowReturn res;
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (GST_PAD_PARENT (pad));
|
||||
|
||||
res = gst_tee_handle_buffer (tee, buffer);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define DEFAULT_SIZE 1024
|
||||
|
||||
static void
|
||||
gst_tee_loop (GstPad * pad)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
GstFlowReturn res;
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (GST_PAD_PARENT (pad));
|
||||
|
||||
res = gst_pad_pull_range (pad, tee->offset, DEFAULT_SIZE, &buffer);
|
||||
if (res != GST_FLOW_OK)
|
||||
goto pause_task;
|
||||
|
||||
res = gst_tee_handle_buffer (tee, buffer);
|
||||
if (res != GST_FLOW_OK)
|
||||
goto pause_task;
|
||||
|
||||
return;
|
||||
|
||||
pause_task:
|
||||
{
|
||||
gst_pad_pause_task (pad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_tee_sink_activate_push (GstPad * pad, gboolean active)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (GST_OBJECT_PARENT (pad));
|
||||
|
||||
tee->sink_mode = active && GST_ACTIVATE_PUSH;
|
||||
|
||||
if (active) {
|
||||
g_return_val_if_fail (tee->has_chain, FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* won't be called until we implement an activate function */
|
||||
static gboolean
|
||||
gst_tee_sink_activate_pull (GstPad * pad, gboolean active)
|
||||
{
|
||||
GstTee *tee;
|
||||
|
||||
tee = GST_TEE (GST_OBJECT_PARENT (pad));
|
||||
|
||||
tee->sink_mode = active && GST_ACTIVATE_PULL;
|
||||
|
||||
if (active) {
|
||||
g_return_val_if_fail (tee->has_sink_loop, FALSE);
|
||||
return gst_pad_start_task (pad, (GstTaskFunction) gst_tee_loop, pad);
|
||||
} else {
|
||||
return gst_pad_stop_task (pad);
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
*
|
||||
* gsttee.h: Header for GstTee 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_TEE_H__
|
||||
#define __GST_TEE_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GST_TYPE_TEE \
|
||||
(gst_tee_get_type())
|
||||
#define GST_TEE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEE,GstTee))
|
||||
#define GST_TEE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEE,GstTeeClass))
|
||||
#define GST_IS_TEE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEE))
|
||||
#define GST_IS_TEE_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEE))
|
||||
|
||||
typedef struct _GstTee GstTee;
|
||||
typedef struct _GstTeeClass GstTeeClass;
|
||||
|
||||
struct _GstTee {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
|
||||
gboolean silent;
|
||||
gboolean has_chain;
|
||||
gboolean has_sink_loop;
|
||||
gint pad_counter;
|
||||
guint64 offset;
|
||||
GstActivateMode sink_mode;
|
||||
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _GstTeeClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_tee_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_TEE_H__ */
|
|
@ -1,868 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||
*
|
||||
* gsttypefindelement.c: element that detects type of stream
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* FIXME: need a better solution for non-seekable streams */
|
||||
|
||||
/* way of operation:
|
||||
* 1) get a list of all typefind functions sorted best to worst
|
||||
* 2) if all elements have been called with all requested data goto 8
|
||||
* 3) call all functions once with all available data
|
||||
* 4) if a function returns a value >= ARG_MAXIMUM goto 8
|
||||
* 5) all functions with a result > ARG_MINIMUM or functions that did not get
|
||||
* all requested data (where peek returned NULL) stay in list
|
||||
* 6) seek to requested offset of best function that still has open data
|
||||
* requests
|
||||
* 7) goto 2
|
||||
* 8) take best available result and use its caps
|
||||
*
|
||||
* The element has two scheduling modes:
|
||||
*
|
||||
* 1) chain based, it will collect buffers and run the typefind function on
|
||||
* the buffer until something is found.
|
||||
* 2) getrange based, it will proxy the getrange function to the sinkpad. It
|
||||
* is assumed that the peer element is happy with whatever format we
|
||||
* eventually read.
|
||||
*
|
||||
* When the element has no connected srcpad, and the sinkpad can operate in
|
||||
* getrange based mode, the element starts its own task to figure out the
|
||||
* type of the stream.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gsttypefindelement.h"
|
||||
#include "gst/gst_private.h"
|
||||
#include "gst/gst-i18n-lib.h"
|
||||
#include "gst/base/gsttypefindhelper.h"
|
||||
|
||||
#include <gst/gsttypefind.h>
|
||||
#include <gst/gstutils.h>
|
||||
#include <gst/gsterror.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
|
||||
#define GST_CAT_DEFAULT gst_type_find_element_debug
|
||||
|
||||
static GstElementDetails gst_type_find_element_details =
|
||||
GST_ELEMENT_DETAILS ("TypeFind",
|
||||
"Generic",
|
||||
"Finds the media type of a stream",
|
||||
"Benjamin Otte <in7y118@public.uni-hamburg.de>");
|
||||
|
||||
/* generic templates */
|
||||
GstStaticPadTemplate type_find_element_sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
GstStaticPadTemplate type_find_element_src_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
/* TypeFind signals and args */
|
||||
enum
|
||||
{
|
||||
HAVE_TYPE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_CAPS,
|
||||
ARG_MINIMUM,
|
||||
ARG_MAXIMUM
|
||||
};
|
||||
enum
|
||||
{
|
||||
MODE_NORMAL, /* act as identity */
|
||||
MODE_TYPEFIND /* do typefinding */
|
||||
};
|
||||
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", \
|
||||
GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
|
||||
GST_TYPE_ELEMENT, _do_init);
|
||||
|
||||
static void gst_type_find_element_dispose (GObject * object);
|
||||
static void gst_type_find_element_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec);
|
||||
static void gst_type_find_element_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
|
||||
#if 0
|
||||
static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
|
||||
#endif
|
||||
|
||||
static gboolean gst_type_find_element_src_event (GstPad * pad,
|
||||
GstEvent * event);
|
||||
static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
|
||||
|
||||
static gboolean gst_type_find_element_handle_event (GstPad * pad,
|
||||
GstEvent * event);
|
||||
static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
|
||||
GstBuffer * buffer);
|
||||
static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
|
||||
guint64 offset, guint length, GstBuffer ** buffer);
|
||||
static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_type_find_element_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
static gboolean gst_type_find_element_activate (GstPad * pad);
|
||||
static gboolean
|
||||
gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
|
||||
|
||||
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gst_type_find_element_have_type (GstTypeFindElement * typefind,
|
||||
guint probability, const GstCaps * caps)
|
||||
{
|
||||
g_assert (typefind->caps == NULL);
|
||||
g_assert (caps != NULL);
|
||||
|
||||
GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT, caps);
|
||||
typefind->caps = gst_caps_copy (caps);
|
||||
gst_pad_set_caps (typefind->src, (GstCaps *) caps);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_type_find_element_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 (&type_find_element_src_template));
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&type_find_element_sink_template));
|
||||
gst_element_class_set_details (gstelement_class,
|
||||
&gst_type_find_element_details);
|
||||
}
|
||||
static void
|
||||
gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
|
||||
|
||||
gobject_class->set_property =
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
|
||||
gobject_class->get_property =
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
|
||||
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
|
||||
|
||||
typefind_class->have_type = gst_type_find_element_have_type;
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_CAPS,
|
||||
g_param_spec_boxed ("caps", _("caps"),
|
||||
_("detected capabilities in stream"), gst_caps_get_type (),
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||
g_param_spec_uint ("minimum", _("minimum"),
|
||||
"minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
|
||||
GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||
g_param_spec_uint ("maximum", _("maximum"),
|
||||
"probability to stop typefinding", GST_TYPE_FIND_MINIMUM,
|
||||
GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
|
||||
|
||||
gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
|
||||
G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
|
||||
gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
|
||||
G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
|
||||
}
|
||||
static void
|
||||
gst_type_find_element_init (GstTypeFindElement * typefind,
|
||||
GstTypeFindElementClass * g_class)
|
||||
{
|
||||
/* sinkpad */
|
||||
typefind->sink =
|
||||
gst_pad_new_from_static_template (&type_find_element_sink_template,
|
||||
"sink");
|
||||
|
||||
gst_pad_set_activate_function (typefind->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
|
||||
gst_pad_set_chain_function (typefind->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
|
||||
gst_pad_set_event_function (typefind->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
|
||||
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
|
||||
|
||||
/* srcpad */
|
||||
typefind->src =
|
||||
gst_pad_new_from_static_template (&type_find_element_src_template, "src");
|
||||
|
||||
gst_pad_set_activatepull_function (typefind->src,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
|
||||
gst_pad_set_checkgetrange_function (typefind->src,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
|
||||
gst_pad_set_getrange_function (typefind->src,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
|
||||
gst_pad_set_event_function (typefind->src,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
|
||||
gst_pad_set_query_function (typefind->src,
|
||||
GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
|
||||
gst_pad_use_fixed_caps (typefind->src);
|
||||
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
|
||||
|
||||
typefind->mode = MODE_TYPEFIND;
|
||||
typefind->caps = NULL;
|
||||
typefind->min_probability = 1;
|
||||
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
|
||||
|
||||
typefind->store = NULL;
|
||||
}
|
||||
static void
|
||||
gst_type_find_element_dispose (GObject * object)
|
||||
{
|
||||
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
|
||||
if (typefind->store) {
|
||||
gst_buffer_unref (typefind->store);
|
||||
typefind->store = NULL;
|
||||
}
|
||||
}
|
||||
static void
|
||||
gst_type_find_element_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstTypeFindElement *typefind;
|
||||
|
||||
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_MINIMUM:
|
||||
typefind->min_probability = g_value_get_uint (value);
|
||||
g_object_notify (object, "minimum");
|
||||
break;
|
||||
case ARG_MAXIMUM:
|
||||
typefind->max_probability = g_value_get_uint (value);
|
||||
g_object_notify (object, "maximum");
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
gst_type_find_element_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstTypeFindElement *typefind;
|
||||
|
||||
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_CAPS:
|
||||
g_value_set_boxed (value, typefind->caps);
|
||||
break;
|
||||
case ARG_MINIMUM:
|
||||
g_value_set_uint (value, typefind->min_probability);
|
||||
break;
|
||||
case ARG_MAXIMUM:
|
||||
g_value_set_uint (value, typefind->max_probability);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
|
||||
{
|
||||
GstTypeFindElement *typefind;
|
||||
gboolean res;
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||
|
||||
res = gst_pad_query (GST_PAD_PEER (typefind->sink), query);
|
||||
if (!res)
|
||||
return FALSE;
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_POSITION:
|
||||
{
|
||||
gint64 peer_pos;
|
||||
GstFormat format;
|
||||
|
||||
if (typefind->store == NULL)
|
||||
return TRUE;
|
||||
|
||||
gst_query_parse_position (query, &format, &peer_pos);
|
||||
|
||||
/* FIXME: this code assumes that there's no discont in the queue */
|
||||
switch (format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
peer_pos -= typefind->store->size;
|
||||
break;
|
||||
default:
|
||||
/* FIXME */
|
||||
break;
|
||||
}
|
||||
gst_query_set_position (query, format, peer_pos);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static const GstEventMask *
|
||||
gst_type_find_element_src_event_mask (GstPad * pad)
|
||||
{
|
||||
static const GstEventMask mask[] = {
|
||||
{GST_EVENT_SEEK,
|
||||
GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
|
||||
GST_SEEK_FLAG_FLUSH},
|
||||
/* add more if you want, event masks suck and need to die anyway */
|
||||
{0,}
|
||||
};
|
||||
|
||||
return mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||
|
||||
if (typefind->mode != MODE_NORMAL) {
|
||||
/* need to do more? */
|
||||
gst_mini_object_unref (GST_MINI_OBJECT (event));
|
||||
return FALSE;
|
||||
}
|
||||
return gst_pad_event_default (pad, event);
|
||||
}
|
||||
typedef struct
|
||||
{
|
||||
GstTypeFindFactory *factory;
|
||||
guint probability;
|
||||
GstCaps *caps;
|
||||
guint requested_size;
|
||||
GstTypeFindElement *self;
|
||||
}
|
||||
TypeFindEntry;
|
||||
|
||||
static inline TypeFindEntry *
|
||||
new_entry (void)
|
||||
{
|
||||
return g_new0 (TypeFindEntry, 1);
|
||||
}
|
||||
static void
|
||||
free_entry (TypeFindEntry * entry)
|
||||
{
|
||||
if (entry->caps)
|
||||
gst_caps_unref (entry->caps);
|
||||
g_free (entry);
|
||||
}
|
||||
static void
|
||||
start_typefinding (GstTypeFindElement * typefind)
|
||||
{
|
||||
g_assert (typefind->possibilities == NULL);
|
||||
|
||||
GST_DEBUG_OBJECT (typefind, "starting typefinding");
|
||||
gst_pad_set_caps (typefind->src, NULL);
|
||||
if (typefind->caps) {
|
||||
gst_caps_replace (&typefind->caps, NULL);
|
||||
}
|
||||
typefind->mode = MODE_TYPEFIND;
|
||||
typefind->stream_length_available = TRUE;
|
||||
typefind->stream_length = 0;
|
||||
}
|
||||
static void
|
||||
stop_typefinding (GstTypeFindElement * typefind)
|
||||
{
|
||||
GstState state;
|
||||
gboolean push_cached_buffers;
|
||||
|
||||
gst_element_get_state (GST_ELEMENT (typefind), &state, NULL,
|
||||
GST_CLOCK_TIME_NONE);
|
||||
|
||||
push_cached_buffers = (state >= GST_STATE_PAUSED);
|
||||
|
||||
GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
|
||||
push_cached_buffers ? " and pushing cached buffers" : "");
|
||||
if (typefind->possibilities != NULL) {
|
||||
/* this should only happen on PAUSED => READY or EOS */
|
||||
GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions",
|
||||
g_list_length (typefind->possibilities));
|
||||
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
|
||||
g_list_free (typefind->possibilities);
|
||||
typefind->possibilities = NULL;
|
||||
}
|
||||
//typefind->mode = MODE_TRANSITION;
|
||||
|
||||
if (typefind->store) {
|
||||
if (!push_cached_buffers) {
|
||||
gst_buffer_unref (typefind->store);
|
||||
} else {
|
||||
typefind->mode = MODE_NORMAL;
|
||||
gst_buffer_set_caps (typefind->store, typefind->caps);
|
||||
gst_pad_push (typefind->src, typefind->store);
|
||||
}
|
||||
typefind->store = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static guint64
|
||||
find_element_get_length (gpointer data)
|
||||
{
|
||||
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||
GstTypeFindElement *typefind = entry->self;
|
||||
GstFormat format = GST_FORMAT_BYTES;
|
||||
|
||||
if (!typefind->stream_length_available) {
|
||||
GST_LOG_OBJECT (entry->self,
|
||||
"'%s' called get_length () but we know it's not available",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||
return 0;
|
||||
}
|
||||
if (entry->self->stream_length == 0) {
|
||||
if (!gst_pad_query_duration (GST_PAD_PEER (entry->self->sink), &format,
|
||||
(gint64 *) & entry->self->stream_length))
|
||||
goto no_length;
|
||||
|
||||
if (format != GST_FORMAT_BYTES) {
|
||||
typefind->stream_length_available = FALSE;
|
||||
entry->self->stream_length = 0;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (entry->self,
|
||||
"'%s' called get_length () and it's %" G_GUINT64_FORMAT " bytes",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
|
||||
}
|
||||
}
|
||||
return entry->self->stream_length;
|
||||
|
||||
no_length:
|
||||
{
|
||||
typefind->stream_length_available = FALSE;
|
||||
GST_DEBUG_OBJECT (entry->self,
|
||||
"'%s' called get_length () but it's not available",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
TypeFindEntry *entry;
|
||||
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_DEBUG_OBJECT (typefind, "got event %d in mode %d", GST_EVENT_TYPE (event),
|
||||
typefind->mode);
|
||||
|
||||
switch (typefind->mode) {
|
||||
case MODE_TYPEFIND:
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
/* this should only happen when we got all available data */
|
||||
entry =
|
||||
(TypeFindEntry *) typefind->possibilities ? typefind->
|
||||
possibilities->data : NULL;
|
||||
if (entry && entry->probability >= typefind->min_probability) {
|
||||
GST_INFO_OBJECT (typefind,
|
||||
"'%s' is the best typefind left after we got all data, using it now (probability %u)",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
|
||||
0, entry->probability, entry->caps);
|
||||
stop_typefinding (typefind);
|
||||
gst_buffer_set_caps (typefind->store, typefind->caps);
|
||||
gst_pad_push (typefind->src, typefind->store);
|
||||
typefind->store = NULL;
|
||||
res = gst_pad_event_default (pad, event);
|
||||
} else {
|
||||
res = gst_pad_event_default (pad, event);
|
||||
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL),
|
||||
(NULL));
|
||||
stop_typefinding (typefind);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gst_mini_object_unref (GST_MINI_OBJECT (event));
|
||||
res = TRUE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MODE_NORMAL:
|
||||
if (FALSE) { // GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) {
|
||||
start_typefinding (typefind);
|
||||
gst_event_unref (event);
|
||||
res = TRUE;
|
||||
} else {
|
||||
res = gst_pad_event_default (pad, event);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
static guint8 *
|
||||
find_peek (gpointer data, gint64 offset, guint size)
|
||||
{
|
||||
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||
|
||||
GST_LOG_OBJECT (entry->self, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
|
||||
if (offset != 0)
|
||||
return NULL;
|
||||
|
||||
if (size <= entry->self->store->size) {
|
||||
return GST_BUFFER_DATA (entry->self->store);
|
||||
} else {
|
||||
entry->requested_size = size;
|
||||
|
||||
GST_LOG_OBJECT (entry->self,
|
||||
"setting requested peek (%" G_GINT64_FORMAT ", %u) on '%s'", offset,
|
||||
size, GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
static void
|
||||
find_suggest (gpointer data, guint probability, const GstCaps * caps)
|
||||
{
|
||||
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||
|
||||
GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, caps);
|
||||
if (((gint) probability) > entry->probability) {
|
||||
entry->probability = probability;
|
||||
gst_caps_replace (&entry->caps, (GstCaps *) caps);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static gint
|
||||
compare_type_find_entry (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
TypeFindEntry *one = (TypeFindEntry *) a;
|
||||
TypeFindEntry *two = (TypeFindEntry *) b;
|
||||
|
||||
if (one->probability == two->probability) {
|
||||
/* FIXME: can be improved by analyzing requests */
|
||||
return 0;
|
||||
} else {
|
||||
return two->probability - one->probability;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static gint
|
||||
compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
|
||||
{
|
||||
return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstTypeFindElement *typefind;
|
||||
GList *entries;
|
||||
TypeFindEntry *entry;
|
||||
GList *walk;
|
||||
GstFlowReturn res = GST_FLOW_OK;
|
||||
GstTypeFind find = { find_peek, find_suggest, NULL, find_element_get_length };
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||
|
||||
switch (typefind->mode) {
|
||||
case MODE_NORMAL:
|
||||
gst_buffer_set_caps (buffer, typefind->caps);
|
||||
return gst_pad_push (typefind->src, buffer);
|
||||
case MODE_TYPEFIND:{
|
||||
gboolean done = TRUE;
|
||||
|
||||
if (typefind->store)
|
||||
typefind->store = gst_buffer_join (typefind->store, buffer);
|
||||
else
|
||||
typefind->store = buffer;
|
||||
|
||||
if (typefind->possibilities == NULL) {
|
||||
/* not yet started, get all typefinding functions into our "queue" */
|
||||
GList *all_factories = gst_type_find_factory_get_list ();
|
||||
|
||||
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
|
||||
g_list_length (all_factories));
|
||||
|
||||
all_factories = g_list_sort (all_factories, compare_type_find_factory);
|
||||
walk = all_factories;
|
||||
while (all_factories) {
|
||||
entry = new_entry ();
|
||||
|
||||
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
|
||||
entry->self = typefind;
|
||||
entry->probability = 0;
|
||||
typefind->possibilities =
|
||||
g_list_prepend (typefind->possibilities, entry);
|
||||
all_factories = g_list_next (all_factories);
|
||||
}
|
||||
gst_plugin_feature_list_free (all_factories);
|
||||
}
|
||||
|
||||
/* call every typefind function once */
|
||||
walk = entries = typefind->possibilities;
|
||||
GST_INFO_OBJECT (typefind, "iterating %u typefinding functions",
|
||||
g_list_length (entries));
|
||||
typefind->possibilities = NULL;
|
||||
while (walk) {
|
||||
find.data = entry = (TypeFindEntry *) walk->data;
|
||||
walk = g_list_next (walk);
|
||||
if (entry->probability == 0) {
|
||||
entry->requested_size = 0;
|
||||
gst_type_find_factory_call_function (entry->factory, &find);
|
||||
} else {
|
||||
typefind->possibilities =
|
||||
g_list_prepend (typefind->possibilities, entry);
|
||||
continue;
|
||||
}
|
||||
if (entry->probability == 0 && entry->requested_size == 0) {
|
||||
GST_DEBUG_OBJECT (typefind,
|
||||
"'%s' was removed - no chance of being the right plugin",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||
free_entry (entry);
|
||||
} else if (entry->probability >= typefind->max_probability) {
|
||||
/* wooha, got caps */
|
||||
GstCaps *found_caps = entry->caps;
|
||||
guint probability = entry->probability;
|
||||
|
||||
GST_INFO_OBJECT (typefind,
|
||||
"'%s' returned %u/%u probability, using it NOW",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory), probability,
|
||||
typefind->max_probability);
|
||||
while (walk) {
|
||||
free_entry ((TypeFindEntry *) walk->data);
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
walk = typefind->possibilities;
|
||||
while (walk) {
|
||||
free_entry (walk->data);
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
g_list_free (typefind->possibilities);
|
||||
typefind->possibilities = NULL;
|
||||
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
|
||||
probability, found_caps);
|
||||
free_entry (entry);
|
||||
} else {
|
||||
typefind->possibilities =
|
||||
g_list_prepend (typefind->possibilities, entry);
|
||||
if (entry->requested_size != 0)
|
||||
done = FALSE;
|
||||
}
|
||||
}
|
||||
g_list_free (entries);
|
||||
|
||||
/* we may now already have caps or we might be left without functions to try */
|
||||
if (typefind->caps) {
|
||||
stop_typefinding (typefind);
|
||||
} else if (typefind->possibilities == NULL) {
|
||||
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
|
||||
stop_typefinding (typefind);
|
||||
return GST_FLOW_ERROR;
|
||||
} else if (done) {
|
||||
TypeFindEntry *best = NULL;
|
||||
|
||||
walk = typefind->possibilities;
|
||||
while (walk) {
|
||||
entry = (TypeFindEntry *) typefind->possibilities->data;
|
||||
if ((!best || entry->probability > best->probability) &&
|
||||
entry->probability >= typefind->min_probability) {
|
||||
best = entry;
|
||||
}
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
if (best) {
|
||||
GST_INFO_OBJECT (typefind,
|
||||
"'%s' is the only typefind left, using it now (probability %u)",
|
||||
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
|
||||
0, entry->probability, entry->caps);
|
||||
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
|
||||
g_list_free (typefind->possibilities);
|
||||
typefind->possibilities = NULL;
|
||||
stop_typefinding (typefind);
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
|
||||
stop_typefinding (typefind);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_type_find_element_checkgetrange (GstPad * srcpad)
|
||||
{
|
||||
GstTypeFindElement *typefind;
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
|
||||
|
||||
return gst_pad_check_pull_range (typefind->sink);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_type_find_element_getrange (GstPad * srcpad,
|
||||
guint64 offset, guint length, GstBuffer ** buffer)
|
||||
{
|
||||
GstTypeFindElement *typefind;
|
||||
GstFlowReturn ret;
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
|
||||
|
||||
ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
|
||||
|
||||
if (ret == GST_FLOW_OK && buffer && *buffer)
|
||||
gst_buffer_set_caps (*buffer, typefind->caps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
|
||||
{
|
||||
GstTypeFindElement *typefind;
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
|
||||
|
||||
return gst_pad_activate_pull (typefind->sink, active);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_type_find_element_activate (GstPad * pad)
|
||||
{
|
||||
GstCaps *found_caps = NULL;
|
||||
GstTypeFindElement *typefind;
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
|
||||
|
||||
/* 1. try to activate in pull mode. if not, switch to push and succeed.
|
||||
2. try to pull type find.
|
||||
3. deactivate pull mode.
|
||||
4. src pad might have been activated push by the state change. deactivate.
|
||||
5. if we didn't find any caps, fail.
|
||||
6. emit have-type; maybe the app connected the source pad to something.
|
||||
7. if the sink pad is activated, we are in pull mode. succeed.
|
||||
otherwise activate both pads in push mode and succeed.
|
||||
*/
|
||||
|
||||
/* 1 */
|
||||
if (!gst_pad_activate_pull (pad, TRUE)) {
|
||||
start_typefinding (typefind);
|
||||
return gst_pad_activate_push (pad, TRUE);
|
||||
}
|
||||
|
||||
/* 2 */
|
||||
{
|
||||
GstPad *peer;
|
||||
|
||||
peer = gst_pad_get_peer (pad);
|
||||
if (peer) {
|
||||
gint64 size;
|
||||
GstFormat format = GST_FORMAT_BYTES;
|
||||
|
||||
gst_pad_query_duration (peer, &format, &size);
|
||||
found_caps = gst_type_find_helper (peer, (guint64) size);
|
||||
gst_object_unref (peer);
|
||||
}
|
||||
}
|
||||
|
||||
/* 3 */
|
||||
gst_pad_activate_pull (pad, FALSE);
|
||||
|
||||
/* 4 */
|
||||
gst_pad_activate_push (typefind->src, FALSE);
|
||||
|
||||
/* 5 */
|
||||
if (!found_caps)
|
||||
return FALSE;
|
||||
|
||||
/* 6 */
|
||||
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
|
||||
0, 100, found_caps);
|
||||
gst_caps_unref (found_caps);
|
||||
typefind->mode = MODE_NORMAL;
|
||||
|
||||
/* 7 */
|
||||
if (gst_pad_is_active (pad))
|
||||
return TRUE;
|
||||
else {
|
||||
gboolean ret;
|
||||
|
||||
ret = gst_pad_activate_push (typefind->src, TRUE);
|
||||
ret &= gst_pad_activate_push (pad, TRUE);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_type_find_element_change_state (GstElement * element,
|
||||
GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret;
|
||||
GstTypeFindElement *typefind;
|
||||
|
||||
typefind = GST_TYPE_FIND_ELEMENT (element);
|
||||
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
gst_caps_replace (&typefind->caps, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||
*
|
||||
* gsttypefindelement.h: element that detects type of stream
|
||||
*
|
||||
* 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_TYPE_FIND_ELEMENT_H__
|
||||
#define __GST_TYPE_FIND_ELEMENT_H__
|
||||
|
||||
#include <gst/gstinfo.h>
|
||||
#include <gst/gstelement.h>
|
||||
/* #include <gst/gstbufferstore.h> */
|
||||
#include "gstbufferstore.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
|
||||
#define GST_TYPE_TYPE_FIND_ELEMENT (gst_type_find_element_get_type ())
|
||||
#define GST_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElement))
|
||||
#define GST_IS_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||
#define GST_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||
#define GST_IS_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||
#define GST_TYPE_FIND_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||
|
||||
typedef struct _GstTypeFindElement GstTypeFindElement;
|
||||
typedef struct _GstTypeFindElementClass GstTypeFindElementClass;
|
||||
|
||||
struct _GstTypeFindElement {
|
||||
GstElement element;
|
||||
|
||||
GstPad * sink;
|
||||
GstPad * src;
|
||||
|
||||
guint min_probability;
|
||||
guint max_probability;
|
||||
GstCaps * caps;
|
||||
|
||||
guint mode;
|
||||
GstBuffer * store;
|
||||
guint64 stream_length;
|
||||
gboolean stream_length_available;
|
||||
|
||||
GList * possibilities;
|
||||
};
|
||||
|
||||
struct _GstTypeFindElementClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*have_type) (GstTypeFindElement *element,
|
||||
guint probability,
|
||||
const GstCaps * caps);
|
||||
};
|
||||
|
||||
GType gst_type_find_element_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */
|
5
gst/indexers/.gitignore
vendored
5
gst/indexers/.gitignore
vendored
|
@ -1,5 +0,0 @@
|
|||
*.bb
|
||||
*.bbg
|
||||
*.da
|
||||
*.def
|
||||
*.gcno
|
|
@ -1,16 +0,0 @@
|
|||
plugin_LTLIBRARIES = libgstindexers.la
|
||||
# file index uses xml
|
||||
if GST_DISABLE_LOADSAVE
|
||||
GST_LOADSAVE_SRC =
|
||||
else
|
||||
GST_LOADSAVE_SRC = gstfileindex.c
|
||||
endif
|
||||
if HAVE_MMAP
|
||||
|
||||
else
|
||||
GST_LOADSAVE_SRC =
|
||||
endif
|
||||
libgstindexers_la_SOURCES = gstindexers.c gstmemindex.c $(GST_LOADSAVE_SRC)
|
||||
libgstindexers_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||
libgstindexers_la_LIBADD = $(GST_OBJ_LIBS)
|
||||
libgstindexers_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
File diff suppressed because it is too large
Load diff
|
@ -1,44 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* 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 <gst/gst_private.h>
|
||||
#include <gst/gstversion.h>
|
||||
#include <gst/gstplugin.h>
|
||||
|
||||
extern gboolean gst_mem_index_plugin_init (GstPlugin * plugin);
|
||||
extern gboolean gst_file_index_plugin_init (GstPlugin * plugin);
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
res &= gst_mem_index_plugin_init (plugin);
|
||||
#ifdef HAVE_MMAP
|
||||
res &= gst_file_index_plugin_init (plugin);
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"gstindexers",
|
||||
"GStreamer core indexers",
|
||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
|
|
@ -1,426 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* 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 <gst/gst.h>
|
||||
|
||||
#define GST_TYPE_MEM_INDEX \
|
||||
(gst_index_get_type ())
|
||||
#define GST_MEM_INDEX(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEM_INDEX, GstMemIndex))
|
||||
#define GST_MEM_INDEX_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEM_INDEX, GstMemIndexClass))
|
||||
#define GST_IS_MEM_INDEX(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEM_INDEX))
|
||||
#define GST_IS_MEM_INDEX_CLASS(obj) \
|
||||
(GST_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEM_INDEX))
|
||||
|
||||
/*
|
||||
* Object model:
|
||||
*
|
||||
* All entries are simply added to a GList first. Then we build
|
||||
* an index to each entry for each id/format
|
||||
*
|
||||
*
|
||||
* memindex
|
||||
* -----------------------------...
|
||||
* ! !
|
||||
* id1 id2
|
||||
* ------------
|
||||
* ! !
|
||||
* format1 format2
|
||||
* ! !
|
||||
* GTree GTree
|
||||
*
|
||||
*
|
||||
* The memindex creates a MemIndexId object for each writer id, a
|
||||
* Hashtable is kept to map the id to the MemIndexId
|
||||
*
|
||||
* The MemIndexId keeps a MemIndexFormatIndex for each format the
|
||||
* specific writer wants indexed.
|
||||
*
|
||||
* The MemIndexFormatIndex keeps all the values of the particular
|
||||
* format in a GTree, The values of the GTree point back to the entry.
|
||||
*
|
||||
* Finding a value for an id/format requires locating the correct GTree,
|
||||
* then do a lookup in the Tree to get the required value.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstFormat format;
|
||||
gint offset;
|
||||
GTree *tree;
|
||||
}
|
||||
GstMemIndexFormatIndex;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint id;
|
||||
GHashTable *format_index;
|
||||
}
|
||||
GstMemIndexId;
|
||||
|
||||
typedef struct _GstMemIndex GstMemIndex;
|
||||
typedef struct _GstMemIndexClass GstMemIndexClass;
|
||||
|
||||
struct _GstMemIndex
|
||||
{
|
||||
GstIndex parent;
|
||||
|
||||
GList *associations;
|
||||
|
||||
GHashTable *id_index;
|
||||
};
|
||||
|
||||
struct _GstMemIndexClass
|
||||
{
|
||||
GstIndexClass parent_class;
|
||||
};
|
||||
|
||||
/* Index signals and args */
|
||||
enum
|
||||
{
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
static void gst_mem_index_class_init (GstMemIndexClass * klass);
|
||||
static void gst_mem_index_init (GstMemIndex * index);
|
||||
static void gst_mem_index_dispose (GObject * object);
|
||||
|
||||
static void gst_mem_index_add_entry (GstIndex * index, GstIndexEntry * entry);
|
||||
static GstIndexEntry *gst_mem_index_get_assoc_entry (GstIndex * index, gint id,
|
||||
GstIndexLookupMethod method, GstAssocFlags flags,
|
||||
GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data);
|
||||
|
||||
#define CLASS(mem_index) GST_MEM_INDEX_CLASS (G_OBJECT_GET_CLASS (mem_index))
|
||||
|
||||
static GstIndex *parent_class = NULL;
|
||||
|
||||
/*static guint gst_mem_index_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
GType
|
||||
gst_mem_index_get_type (void)
|
||||
{
|
||||
static GType mem_index_type = 0;
|
||||
|
||||
if (!mem_index_type) {
|
||||
static const GTypeInfo mem_index_info = {
|
||||
sizeof (GstMemIndexClass),
|
||||
NULL,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_mem_index_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstMemIndex),
|
||||
1,
|
||||
(GInstanceInitFunc) gst_mem_index_init,
|
||||
NULL
|
||||
};
|
||||
|
||||
mem_index_type =
|
||||
g_type_register_static (GST_TYPE_INDEX, "GstMemIndex", &mem_index_info,
|
||||
0);
|
||||
}
|
||||
return mem_index_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_class_init (GstMemIndexClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstIndexClass *gstindex_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstindex_class = (GstIndexClass *) klass;
|
||||
|
||||
parent_class = g_type_class_ref (GST_TYPE_INDEX);
|
||||
|
||||
gobject_class->dispose = gst_mem_index_dispose;
|
||||
|
||||
gstindex_class->add_entry = gst_mem_index_add_entry;
|
||||
gstindex_class->get_assoc_entry = gst_mem_index_get_assoc_entry;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_init (GstMemIndex * index)
|
||||
{
|
||||
GST_DEBUG ("created new mem index");
|
||||
|
||||
index->associations = NULL;
|
||||
index->id_index = g_hash_table_new (g_int_hash, g_int_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_dispose (GObject * object)
|
||||
{
|
||||
//GstMemIndex *memindex = GST_MEM_INDEX (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_add_id (GstIndex * index, GstIndexEntry * entry)
|
||||
{
|
||||
GstMemIndex *memindex = GST_MEM_INDEX (index);
|
||||
GstMemIndexId *id_index;
|
||||
|
||||
id_index = g_hash_table_lookup (memindex->id_index, &entry->id);
|
||||
|
||||
if (!id_index) {
|
||||
id_index = g_new0 (GstMemIndexId, 1);
|
||||
|
||||
id_index->id = entry->id;
|
||||
id_index->format_index = g_hash_table_new (g_int_hash, g_int_equal);
|
||||
g_hash_table_insert (memindex->id_index, &id_index->id, id_index);
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
mem_index_compare (gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
GstMemIndexFormatIndex *index = user_data;
|
||||
gint64 val1, val2;
|
||||
gint64 diff;
|
||||
|
||||
val1 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) a), index->offset);
|
||||
val2 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) b), index->offset);
|
||||
|
||||
diff = (val2 - val1);
|
||||
|
||||
return (diff == 0 ? 0 : (diff > 0 ? 1 : -1));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_index_format (GstMemIndexId * id_index, GstIndexEntry * entry,
|
||||
gint assoc)
|
||||
{
|
||||
GstMemIndexFormatIndex *index;
|
||||
GstFormat *format;
|
||||
|
||||
format = &GST_INDEX_ASSOC_FORMAT (entry, assoc);
|
||||
|
||||
index = g_hash_table_lookup (id_index->format_index, format);
|
||||
|
||||
if (!index) {
|
||||
index = g_new0 (GstMemIndexFormatIndex, 1);
|
||||
|
||||
index->format = *format;
|
||||
index->offset = assoc;
|
||||
index->tree = g_tree_new_with_data (mem_index_compare, index);
|
||||
|
||||
g_hash_table_insert (id_index->format_index, &index->format, index);
|
||||
}
|
||||
|
||||
g_tree_insert (index->tree, entry, entry);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_add_association (GstIndex * index, GstIndexEntry * entry)
|
||||
{
|
||||
GstMemIndex *memindex = GST_MEM_INDEX (index);
|
||||
GstMemIndexId *id_index;
|
||||
|
||||
memindex->associations = g_list_prepend (memindex->associations, entry);
|
||||
|
||||
id_index = g_hash_table_lookup (memindex->id_index, &entry->id);
|
||||
if (id_index) {
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) {
|
||||
gst_mem_index_index_format (id_index, entry, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_add_object (GstIndex * index, GstIndexEntry * entry)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_add_format (GstIndex * index, GstIndexEntry * entry)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mem_index_add_entry (GstIndex * index, GstIndexEntry * entry)
|
||||
{
|
||||
GST_LOG_OBJECT (index, "added this entry");
|
||||
|
||||
switch (entry->type) {
|
||||
case GST_INDEX_ENTRY_ID:
|
||||
gst_mem_index_add_id (index, entry);
|
||||
break;
|
||||
case GST_INDEX_ENTRY_ASSOCIATION:
|
||||
gst_mem_index_add_association (index, entry);
|
||||
break;
|
||||
case GST_INDEX_ENTRY_OBJECT:
|
||||
gst_mem_index_add_object (index, entry);
|
||||
break;
|
||||
case GST_INDEX_ENTRY_FORMAT:
|
||||
gst_mem_index_add_format (index, entry);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 value;
|
||||
GstMemIndexFormatIndex *index;
|
||||
gboolean exact;
|
||||
GstIndexEntry *lower;
|
||||
gint64 low_diff;
|
||||
GstIndexEntry *higher;
|
||||
gint64 high_diff;
|
||||
}
|
||||
GstMemIndexSearchData;
|
||||
|
||||
static gint
|
||||
mem_index_search (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
GstMemIndexSearchData *data = (GstMemIndexSearchData *) b;
|
||||
GstMemIndexFormatIndex *index = data->index;
|
||||
gint64 val1, val2;
|
||||
gint64 diff;
|
||||
|
||||
val1 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) a), index->offset);
|
||||
val2 = data->value;
|
||||
|
||||
diff = (val1 - val2);
|
||||
if (diff == 0)
|
||||
return 0;
|
||||
|
||||
/* exact matching, don't update low/high */
|
||||
if (data->exact)
|
||||
return (diff > 0 ? 1 : -1);
|
||||
|
||||
if (diff < 0) {
|
||||
if (diff > data->low_diff) {
|
||||
data->low_diff = diff;
|
||||
data->lower = (GstIndexEntry *) a;
|
||||
}
|
||||
diff = -1;
|
||||
} else {
|
||||
if (diff < data->high_diff) {
|
||||
data->high_diff = diff;
|
||||
data->higher = (GstIndexEntry *) a;
|
||||
}
|
||||
diff = 1;
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
static GstIndexEntry *
|
||||
gst_mem_index_get_assoc_entry (GstIndex * index, gint id,
|
||||
GstIndexLookupMethod method,
|
||||
GstAssocFlags flags,
|
||||
GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data)
|
||||
{
|
||||
GstMemIndex *memindex = GST_MEM_INDEX (index);
|
||||
GstMemIndexId *id_index;
|
||||
GstMemIndexFormatIndex *format_index;
|
||||
GstIndexEntry *entry;
|
||||
GstMemIndexSearchData data;
|
||||
|
||||
id_index = g_hash_table_lookup (memindex->id_index, &id);
|
||||
if (!id_index)
|
||||
return NULL;
|
||||
|
||||
format_index = g_hash_table_lookup (id_index->format_index, &format);
|
||||
if (!format_index)
|
||||
return NULL;
|
||||
|
||||
data.value = value;
|
||||
data.index = format_index;
|
||||
data.exact = (method == GST_INDEX_LOOKUP_EXACT);
|
||||
|
||||
/* setup data for low/high checks if we are not looking
|
||||
* for an exact match */
|
||||
if (!data.exact) {
|
||||
data.low_diff = G_MININT64;
|
||||
data.lower = NULL;
|
||||
data.high_diff = G_MAXINT64;
|
||||
data.higher = NULL;
|
||||
}
|
||||
|
||||
entry = g_tree_search (format_index->tree, mem_index_search, &data);
|
||||
|
||||
/* get the low/high values if we're not exact */
|
||||
if (entry == NULL && !data.exact) {
|
||||
if (method == GST_INDEX_LOOKUP_BEFORE)
|
||||
entry = data.lower;
|
||||
else if (method == GST_INDEX_LOOKUP_AFTER) {
|
||||
entry = data.higher;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
if ((GST_INDEX_ASSOC_FLAGS (entry) & flags) != flags) {
|
||||
GList *l_entry = g_list_find (memindex->associations, entry);
|
||||
|
||||
entry = NULL;
|
||||
|
||||
while (l_entry) {
|
||||
entry = (GstIndexEntry *) l_entry->data;
|
||||
|
||||
if (entry->id == id && (GST_INDEX_ASSOC_FLAGS (entry) & flags) == flags)
|
||||
break;
|
||||
|
||||
if (method == GST_INDEX_LOOKUP_BEFORE)
|
||||
l_entry = g_list_next (l_entry);
|
||||
else if (method == GST_INDEX_LOOKUP_AFTER) {
|
||||
l_entry = g_list_previous (l_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_mem_index_plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
GstIndexFactory *factory;
|
||||
|
||||
factory = gst_index_factory_new ("memindex",
|
||||
"A index that stores entries in memory", gst_mem_index_get_type ());
|
||||
|
||||
if (factory == NULL) {
|
||||
g_warning ("failed to create memindex factory");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_FEATURE (factory)->plugin_name = g_strdup (plugin->desc.name);
|
||||
GST_PLUGIN_FEATURE (factory)->loaded = TRUE;
|
||||
|
||||
gst_registry_add_feature (gst_registry_get_default (),
|
||||
GST_PLUGIN_FEATURE (factory));
|
||||
|
||||
return TRUE;
|
||||
}
|
Loading…
Reference in a new issue