mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +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