initial checkin of typefind rewrite - doesn't work yet, but you may want to fix it :) - it compiles though

Original commit message from CVS:
initial checkin of typefind rewrite - doesn't work yet, but you may want to fix it :) - it compiles though
This commit is contained in:
Benjamin Otte 2003-10-23 01:27:07 +00:00
parent 208c0e3089
commit 493ba84f4c
44 changed files with 4253 additions and 624 deletions

View file

@ -372,8 +372,6 @@ GST_SUBSYSTEM_DISABLE(GST_DEBUG,[debugging subsystem])
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_LOADSAVE, true)
GST_SUBSYSTEM_DISABLE(LOADSAVE,[pipeline XML load/save])
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_TYPEFIND, true)
GST_SUBSYSTEM_DISABLE(TYPEFIND,[typefind plugin],)
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_AUTOPLUG, true)
GST_SUBSYSTEM_DISABLE(AUTOPLUG,[autoplugger subsystem])
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_PARSE, true)
@ -562,12 +560,12 @@ gst/indexers/Makefile
gst/elements/Makefile
gst/parse/Makefile
gst/schedulers/Makefile
gst/types/Makefile
gst/registries/Makefile
libs/Makefile
libs/gst/Makefile
libs/gst/getbits/Makefile
libs/gst/bytestream/Makefile
libs/gst/control/Makefile
libs/gst/getbits/Makefile
libs/ext/Makefile
po/Makefile.in
tests/Makefile

View file

@ -15,12 +15,6 @@ else
GST_LOADSAVE_SRC = gstxml.c
endif
if GST_DISABLE_TYPEFIND
GST_TYPEFIND_SRC =
else
GST_TYPEFIND_SRC = gsttypefind.c
endif
if GST_DISABLE_AUTOPLUG
GST_AUTOPLUG_SRC =
GST_AUTOPLUG_DIRS =
@ -81,10 +75,10 @@ else
GST_URI_SRC = gsturi.c
endif
EXTRA_libgstreamer_@GST_MAJORMINOR@_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gsttypefind.c gstparse.c gstautoplug.c gsttrace.c
EXTRA_libgstreamer_@GST_MAJORMINOR@_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gstparse.c gstautoplug.c gsttrace.c
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . $(GST_AUTOPLUG_DIRS) elements schedulers types $(GST_INDEX_DIRS)
DIST_SUBDIRS = autoplug elements parse registries schedulers types indexers
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . $(GST_AUTOPLUG_DIRS) elements schedulers $(GST_INDEX_DIRS)
DIST_SUBDIRS = autoplug elements parse registries schedulers indexers
libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
gst.c \
@ -96,7 +90,6 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
gstbin.c \
gstbuffer.c \
gstbufferpool-default.c \
gstbytestream.c \
gstcaps.c \
gstclock.c \
gstcpu.c \
@ -124,8 +117,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
gstthreaddummy.c \
$(GST_TRACE_SRC) \
gsttrashstack.c \
gsttype.c \
$(GST_TYPEFIND_SRC) \
gsttypefind.c \
$(GST_URI_SRC) \
gsturitype.c \
gstutils.c \
@ -153,12 +145,10 @@ gst_headers = \
gst.h \
gstatomic.h \
gstobject.h \
gsttypes.h \
gstautoplug.h \
gstbin.h \
gstbuffer.h \
gstbufferpool-default.h \
gstbytestream.h \
gstcaps.h \
gstclock.h \
gstcompat.h \
@ -187,8 +177,8 @@ gst_headers = \
gstthread.h \
gsttrace.h \
gsttrashstack.h \
gsttype.h \
gsttypefind.h \
gsttypes.h \
gsturi.h \
gsturitype.h \
gstutils.h \

View file

@ -410,82 +410,96 @@ gst_spider_identity_src_loop (GstSpiderIdentity *ident)
}
/* This loop function is only needed when typefinding.
*/
typedef struct {
GstBuffer *buffer;
guint best_probability;
GstCaps *caps;
} SpiderTypeFind;
guint8 *
spider_find_peek (gpointer data, gint64 offset, guint size)
{
SpiderTypeFind *find = (SpiderTypeFind *) data;
gint64 buffer_offset = GST_BUFFER_OFFSET_IS_VALID (find->buffer) ?
GST_BUFFER_OFFSET (find->buffer) : 0;
if (offset >= buffer_offset && offset + size <= buffer_offset + GST_BUFFER_SIZE (find->buffer)) {
return GST_BUFFER_DATA (find->buffer) + offset - buffer_offset;
} else {
return NULL;
}
}
void spider_find_suggest (gpointer data, guint probability, GstCaps *caps)
{
SpiderTypeFind *find = (SpiderTypeFind *) data;
if (probability > find->best_probability) {
gst_caps_replace (&find->caps, caps);
find->best_probability = probability;
}
}
static void
gst_spider_identity_sink_loop_type_finding (GstSpiderIdentity *ident)
{
GstBuffer *buf = NULL;
GList *type_list;
GstCaps *caps;
GstByteStream *bs;
GstData *data;
GList *type_list = NULL;
GstTypeFind gst_find;
SpiderTypeFind find;
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
/* get a bytestream object */
bs = gst_bytestream_new (ident->sink);
if (gst_bytestream_peek (bs, &buf, 1) != 1 || !buf) {
buf = NULL;
g_warning ("Failed to read fake buffer - serious idiocy going on here");
goto end;
} else {
gst_buffer_unref (buf);
buf = NULL;
data = gst_pad_pull (ident->sink);
while (!GST_IS_BUFFER (data)) {
gst_spider_identity_chain (ident->sink, GST_BUFFER (data));
data = gst_pad_pull (ident->sink);
}
/* maybe there are already valid caps now? */
if ((caps = gst_pad_get_caps (ident->sink)) != NULL) {
if ((find.caps = gst_pad_get_caps (ident->sink)) != NULL) {
gst_caps_ref (find.caps); /* it's unrefed later below */
goto plug;
}
/* now do the actual typefinding with the supplied buffer */
type_list = (GList *) gst_type_get_list ();
type_list = gst_type_find_factory_get_list ();
find.buffer = GST_BUFFER (data);
find.best_probability = 0;
find.caps = NULL;
gst_find.data = &find;
gst_find.peek = spider_find_peek;
gst_find.suggest = spider_find_suggest;
while (type_list) {
GstType *type = (GstType *) type_list->data;
GSList *factories = type->factories;
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (type_list->data);
while (factories) {
GstTypeFactory *factory = GST_TYPE_FACTORY (factories->data);
GstTypeFindFunc typefindfunc = (GstTypeFindFunc)factory->typefindfunc;
GST_DEBUG ("trying typefind function %s", GST_PLUGIN_FEATURE_NAME (factory));
if (typefindfunc && (caps = typefindfunc (bs, factory))) {
GST_INFO ("typefind function %s found caps", GST_PLUGIN_FEATURE_NAME (factory));
if (gst_pad_try_set_caps (ident->src, caps) <= 0) {
g_warning ("typefind: found type but peer didn't accept it");
gst_caps_sink (caps);
} else {
goto plug;
}
}
factories = g_slist_next (factories);
}
GST_DEBUG ("trying typefind function %s", GST_PLUGIN_FEATURE_NAME (factory));
gst_type_find_factory_call_function (factory, &gst_find);
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
goto plug;
type_list = g_list_next (type_list);
}
if (find.best_probability > 0)
goto plug;
gst_element_error(GST_ELEMENT(ident), "Could not find media type", NULL);
buf = GST_BUFFER (gst_event_new (GST_EVENT_EOS));
find.buffer = GST_BUFFER (gst_event_new (GST_EVENT_EOS));
end:
/* remove loop function */
gst_element_set_loop_function (GST_ELEMENT (ident),
(GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
/* push the buffer */
gst_spider_identity_chain (ident->sink, buf);
/* bytestream no longer needed */
gst_bytestream_destroy (bs);
gst_spider_identity_chain (ident->sink, find.buffer);
return;
plug:
gst_caps_debug (caps, "spider starting caps");
gst_caps_sink (caps);
GST_INFO ("typefind function found caps");
g_assert (gst_pad_try_set_caps (ident->src, find.caps) > 0);
gst_caps_debug (find.caps, "spider starting caps");
gst_caps_unref (find.caps);
gst_spider_identity_plug (ident);
gst_bytestream_read (bs, &buf, bs->listavail);
goto end;
}

View file

@ -1,40 +1,51 @@
# FIXME:
# need to get gstbufferstore.[ch] into its own lib, preferrably
# libs/gst/buifferstore
# This requires building libs/gst before this dir, which we currently don't
# do.
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
plugin_LTLIBRARIES = libgstelements.la
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
libgstelements_la_SOURCES = \
gstaggregator.c \
gstbufferstore.c \
gstelements.c \
gstfakesrc.c \
gstidentity.c \
gstfakesink.c \
gstfilesrc.c \
gstfakesrc.c \
gstfilesink.c \
gstfdsrc.c \
gstfilesrc.c \
gstfdsink.c \
gstfdsrc.c \
gstidentity.c \
gstmd5sink.c \
gstmultidisksrc.c \
gstpipefilter.c \
gsttee.c \
gstaggregator.c \
gstshaper.c \
gststatistics.c \
gstmd5sink.c
gsttee.c \
gsttypefindelement.c
libgstelements_la_CFLAGS = $(GST_CFLAGS)
libgstelements_la_LIBADD =
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = \
gstfakesrc.h \
gstidentity.h \
gstfakesink.h \
gstfilesink.h \
gstfdsrc.h \
gstmultidisksrc.h \
gstfdsink.h \
gstpipefilter.h \
gsttee.h \
gstaggregator.h \
gstshaper.h \
gststatistics.h \
gstbufferstore.h \
gstfakesink.h \
gstfakesrc.h \
gstfdsink.h \
gstfdsrc.h \
gstfilesink.h \
gstfilesrc.h \
gstmd5sink.h
gstidentity.h \
gstmd5sink.h \
gstmultidisksrc.h \
gstpipefilter.h \
gstshaper.h \
gststatistics.h \
gsttee.h \
gsttypefindelement.h

View file

@ -0,0 +1,427 @@
/* 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 <string.h>
GST_DEBUG_CATEGORY (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_class_init (gpointer g_class,
gpointer class_data);
static void gst_buffer_store_init (GTypeInstance * instance,
gpointer g_class);
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 GObjectClass *parent_class = NULL;
static guint gst_buffer_store_signals[LAST_SIGNAL] = { 0 };
GType
gst_buffer_store_get_type (void)
{
static GType store_type = 0;
if (!store_type) {
static const GTypeInfo store_info = {
sizeof (GstBufferStoreClass),
NULL,
NULL,
gst_buffer_store_class_init,
NULL,
NULL,
sizeof (GstBufferStore),
0,
gst_buffer_store_init,
NULL
};
store_type = g_type_register_static (G_TYPE_OBJECT,
"GstBufferStore",
&store_info, 0);
/* FIXME: better description anyone? */
GST_DEBUG_CATEGORY_INIT (gst_buffer_store_debug, "bufferstore", 0, "store all data");
}
return store_type;
}
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_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstBufferStoreClass *store_class;
gobject_class = G_OBJECT_CLASS (g_class);
store_class = GST_BUFFER_STORE_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_class);
gobject_class->dispose = gst_buffer_store_dispose;
gst_buffer_store_signals[CLEARED] = g_signal_new ("cleared",
G_TYPE_FROM_CLASS (g_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 (g_class), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstBufferStoreClass, buffer_added), continue_accu, NULL,
gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
store_class->cleared = gst_buffer_store_cleared_func;
store_class->buffer_added = gst_buffer_store_add_buffer_func;
}
static void
gst_buffer_store_init (GTypeInstance *instance, gpointer g_class)
{
GstBufferStore *store = GST_BUFFER_STORE (instance);
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)
{
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 */
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_data_ref (GST_DATA (buffer));
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));
/* 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_OFFSET (current)) {
g_assert (needed_size == GST_BUFFER_OFFSET (current)); /* we have no overlapping data */
buffer = NULL;
} 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);
buffer = sub;
} else {
gst_data_ref (GST_DATA (buffer));
}
/* replace current buffer with new one */
gst_data_unref (GST_DATA (current_list->data));
current_list->data = buffer;
buffer = NULL;
break;
}
} else if (GST_BUFFER_OFFSET (current) > GST_BUFFER_OFFSET (buffer)) {
GList *previous = g_list_previous (current_list);
guint64 start_offset = previous ?
GST_BUFFER_OFFSET (previous->data) + GST_BUFFER_SIZE (previous->data) : 0;
if (start_offset == GST_BUFFER_OFFSET (current)) {
buffer = NULL;
break;
} else {
/* we have data to insert */
if (start_offset > GST_BUFFER_OFFSET (buffer) ||
GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer) > GST_BUFFER_OFFSET (current)) {
/* need a subbuffer */
start_offset = GST_BUFFER_OFFSET (buffer) > start_offset ? 0 :
start_offset - GST_BUFFER_OFFSET (buffer);
GstBuffer* sub = gst_buffer_create_sub (buffer, start_offset,
MIN (GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (current) - start_offset));
buffer = sub;
} else {
gst_data_ref (GST_DATA (buffer));
}
store->buffers = g_list_insert_before (store->buffers, walk, buffer);
buffer = NULL;
break;
}
}
}
if (buffer) {
gst_data_ref (GST_DATA (buffer));
if (current_list) {
g_list_append (current_list, buffer);
} else {
g_assert (store->buffers == NULL);
store->buffers = g_list_prepend (NULL, buffer);
}
}
return TRUE;
}
}
static void
gst_buffer_store_cleared_func (GstBufferStore *store)
{
g_list_foreach (store->buffers, (GFunc) gst_data_unref, NULL);
g_list_free (store->buffers);
store->buffers = NULL;
}
/**
* gst_buffer_store_new:
*
* Creates a new bufferstore.
*
* Returns: the new bufferstore.
*/
GstBufferStore *
gst_buffer_store_new (void)
{
return GST_BUFFER_STORE (g_object_new (GST_TYPE_BUFFER_STORE, NULL));
}
/**
* gst_buffer_store_clear:
* @store: a bufferstore
*
* Clears the buffer store. All buffers are removed and the buffer store
* behaves like it was just created.
*/
/* FIXME: call this function _reset ? */
void
gst_buffer_store_clear (GstBufferStore *store)
{
g_return_if_fail (GST_IS_BUFFER_STORE (store));
g_signal_emit (store, gst_buffer_store_signals [CLEARED], 0, NULL);
}
/**
* gst_buffer_store_add_buffer:
* @store: a bufferstore
* @buffer: the buffer to add
*
* Adds a buffer to the buffer store.
*
* Returns: TRUE, if the buffer was added, FALSE if an error occured.
*/
gboolean
gst_buffer_store_add_buffer (GstBufferStore *store, GstBuffer *buffer)
{
gboolean ret;
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
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;
guint64 cur_offset;
gboolean have_offset;
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;
cur_offset = 0;
}
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 &&
GST_BUFFER_SIZE (current) == size) {
GST_LOG_OBJECT (store, "found matching buffer %p for offset %"G_GUINT64_FORMAT" and size %u",
current, offset, size);
ret = current;
gst_data_ref (GST_DATA (ret));
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_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 &&
cur_offset + GST_BUFFER_SIZE (current) != GST_BUFFER_OFFSET (walk->data))) {
GST_DEBUG_OBJECT (store, "not all data for offset %"G_GUINT64_FORMAT" and size %u available, aborting",
offset, size);
gst_data_unref (GST_DATA (ret));
ret = NULL;
break;
}
current = GST_BUFFER (walk->data);
walk = g_list_next (walk);
tmp = MIN (GST_BUFFER_SIZE (current), size);
memcpy (data, GST_BUFFER_DATA (current), tmp);
size -= tmp;
}
}
if (!have_offset) {
cur_offset += GST_BUFFER_SIZE (current);
}
}
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;
guint64 cur_offset;
gboolean have_offset;
gboolean counting = FALSE;
GstBuffer *current;
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;
cur_offset = 0;
}
while (walk) {
if (have_offset &&
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;
}

View file

@ -0,0 +1,73 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.h: keep an easily accessible list of all buffers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_BUFFER_STORE_H__
#define __GST_BUFFER_STORE_H__
#include <gst/gstbuffer.h>
#include <gst/gstinfo.h>
#include <gst/gstmarshal.h>
G_BEGIN_DECLS
#define GST_TYPE_BUFFER_STORE (gst_buffer_store_get_type ())
#define GST_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_BUFFER_STORE, GstBufferStore))
#define GST_IS_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_BUFFER_STORE))
#define GST_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
#define GST_IS_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_BUFFER_STORE))
#define GST_BUFFER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
typedef struct _GstBufferStore GstBufferStore;
typedef struct _GstBufferStoreClass GstBufferStoreClass;
struct _GstBufferStore {
GObject object;
GList * buffers;
};
struct _GstBufferStoreClass {
GObjectClass parent_class;
/* signals */
void (* cleared) (GstBufferStore * store);
gboolean (* buffer_added) (GstBufferStore * store,
GstBuffer * buffer);
};
GType gst_buffer_store_get_type (void);
GstBufferStore * gst_buffer_store_new (void);
void gst_buffer_store_clear (GstBufferStore * store);
gboolean gst_buffer_store_add_buffer (GstBufferStore * store,
GstBuffer * buffer);
GstBuffer * gst_buffer_store_get_buffer (GstBufferStore * store,
guint64 offset,
guint size);
guint gst_buffer_store_get_size (GstBufferStore * store,
guint64 offset);
G_END_DECLS
#endif /* __GST_BUFFER_STORE_H__ */

View file

@ -27,20 +27,21 @@
#include <gst/gst.h>
#include "gstfilesrc.h"
#include "gstfilesink.h"
#include "gstidentity.h"
#include "gstaggregator.h"
#include "gstfakesink.h"
#include "gstfakesrc.h"
#include "gstfdsink.h"
#include "gstfdsrc.h"
#include "gstfilesink.h"
#include "gstfilesrc.h"
#include "gstidentity.h"
#include "gstmd5sink.h"
#include "gstmultidisksrc.h"
#include "gstpipefilter.h"
#include "gsttee.h"
#include "gstaggregator.h"
#include "gstshaper.h"
#include "gststatistics.h"
#include "gstmd5sink.h"
#include "gsttee.h"
#include "gsttypefindelement.h"
struct _elements_entry {
@ -55,20 +56,21 @@ extern GType gst_filesrc_get_type(void);
extern GstElementDetails gst_filesrc_details;
static struct _elements_entry _elements[] = {
{ "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, gst_fakesrc_factory_init },
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, gst_fakesink_factory_init },
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
{ "filesrc", gst_filesrc_get_type, &gst_filesrc_details, NULL },
{ "filesink", gst_filesink_get_type, &gst_filesink_details, NULL },
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
{ "multidisksrc", gst_multidisksrc_get_type, &gst_multidisksrc_details, NULL },
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
{ "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
{ "shaper", gst_shaper_get_type, &gst_shaper_details, gst_shaper_factory_init },
{ "statistics", gst_statistics_get_type, &gst_statistics_details, NULL },
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
{ "typefind", gst_type_find_element_get_type, &gst_type_find_element_details, NULL },
{ NULL, 0 },
};
@ -80,20 +82,21 @@ plugin_init (GModule *module, GstPlugin *plugin)
gst_plugin_set_longname (plugin, "Standard GST Elements");
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "fakesink", 0, "filesink element");
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0, "filesink element");
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
GST_DEBUG_CATEGORY_INIT (gst_multidisksrc_debug, "multidisksrc", 0, "multidisksrc element");
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", 0, "typefind element");
while (_elements[i].name) {
factory = gst_element_factory_new (_elements[i].name,
@ -112,12 +115,10 @@ plugin_init (GModule *module, GstPlugin *plugin)
_elements[i].factoryinit (factory);
}
/* g_print("added factory '%s'\n",_elements[i].name); */
i++;
}
/* INFO (GST_INFO_PLUGIN_LOAD,"gstelements: loaded %d standard elements", i);*/
return TRUE;
}

563
gst/elements/gsttypefind.c Normal file
View file

@ -0,0 +1,563 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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.
*/
/* 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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gsttypefindelement.h"
#include "gst/gst_private.h"
#include <gst/gsttypefind.h>
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
#define GST_CAT_DEFAULT gst_type_find_element_debug
GstElementDetails gst_type_find_element_details = {
"TypeFind",
"Generic",
"LGPL",
"Finds the media type of a stream",
VERSION,
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
"(C) 2003",
};
/* generic templates */
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_CAPS_ANY
);
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_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 */
};
static void gst_type_find_element_class_init (gpointer g_class,
gpointer class_data);
static void gst_type_find_element_init (GTypeInstance *instance,
gpointer g_class);
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);
static void gst_type_find_element_chain (GstPad * sinkpad,
GstData * data);
static GstElementStateReturn
gst_type_find_element_change_state (GstElement * element);
static GstElementClass *parent_class = NULL;
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
GType
gst_type_find_element_get_type (void)
{
static GType typefind_type = 0;
if (!typefind_type) {
static const GTypeInfo typefind_info = {
sizeof (GstTypeFindElementClass),
NULL,
NULL,
gst_type_find_element_class_init,
NULL,
NULL,
sizeof (GstTypeFindElement),
0,
gst_type_find_element_init,
NULL
};
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstTypeFindElement",
&typefind_info, 0);
}
return typefind_type;
}
static void
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
{
gchar *caps_str;
g_assert (typefind->caps == NULL);
caps_str = gst_caps_to_string (caps);
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
g_free (caps_str);
gst_caps_replace (&typefind->caps, caps);
if (!gst_pad_try_set_caps (typefind->src, caps)) {
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
}
}
static void
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstTypeFindElementClass *typefind_class;
gobject_class = G_OBJECT_CLASS (g_class);
gstelement_class = GST_ELEMENT_CLASS (g_class);
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_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);
g_object_class_install_property (gobject_class, ARG_CAPS,
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
GST_TYPE_CAPS, 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 (g_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);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
typefind_class->have_type = gst_type_find_element_have_type;
}
static void
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
/* sinkpad */
typefind->sink = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
gst_pad_set_chain_function (typefind->sink,
gst_type_find_element_chain);
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
/* srcpad */
typefind->src = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
typefind->caps = NULL;
typefind->min_probability = 1;
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
typefind->store = gst_buffer_store_new ();
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_type_find_element_dispose (GObject *object)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
if (typefind->store) {
g_object_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 void
start_typefinding (GstTypeFindElement *typefind)
{
g_assert (typefind->caps == NULL);
typefind->mode = MODE_TYPEFIND;
}
static void
stop_typefinding (GstTypeFindElement *typefind, gboolean push_cached_buffers)
{
/* stop all typefinding and set mode back to normal */
g_assert (typefind->possibilities == NULL);
typefind->mode = MODE_NORMAL;
if (push_cached_buffers) {
guint size = gst_buffer_store_get_size (typefind->store, 0);
GstBuffer *buffer = gst_buffer_store_get_buffer (typefind->store, 0, size);
if (buffer) {
gst_pad_push (typefind->sink, GST_DATA (buffer));
} else {
size = 0;
}
gst_pad_send_event (GST_PAD_PEER (typefind->sink),
gst_event_new_seek (GST_SEEK_METHOD_SET, size));
}
gst_buffer_store_clear (typefind->store);
}
static void
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
{
gst_pad_event_default (pad, event);
}
typedef struct {
GstTypeFindFactory * factory;
gint probability;
GstCaps * caps;
gint64 requested_offset;
guint requested_size;
GList * buffers;
GstTypeFindElement * self;
} TypeFindEntry;
static void
free_entry_buffers (TypeFindEntry *entry)
{
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
g_list_free (entry->buffers);
entry->buffers = NULL;
}
static void
free_entry (TypeFindEntry *entry)
{
free_entry_buffers (entry);
if (entry->caps)
gst_caps_unref (entry->caps);
g_free (entry);
}
static guint64
find_element_get_length (gpointer data)
{
TypeFindEntry *entry = (TypeFindEntry *) data;
GstTypeFindElement *typefind = entry->self;
GstFormat format = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length ()",
GST_PLUGIN_FEATURE_NAME (entry->factory));
if (!typefind->stream_length_available)
return 0;
if (entry->self->stream_length == 0) {
typefind->stream_length_available = gst_pad_query (entry->self->sink, GST_QUERY_TOTAL,
&format, &entry->self->stream_length);
if (format != GST_FORMAT_BYTES)
typefind->stream_length_available = FALSE;
if (!typefind->stream_length_available)
return 0;
}
return entry->self->stream_length;
}
static guint8 *
find_peek (gpointer data, gint64 offset, guint size)
{
GstBuffer *buf;
TypeFindEntry *entry = (TypeFindEntry *) data;
GST_DEBUG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
if (offset >= 0) {
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
} else {
/* FIXME: can we do this easily without querying length? */
guint64 length = find_element_get_length (data);
if (length == 0) {
buf = NULL;
} else {
buf = gst_buffer_store_get_buffer (entry->self->store, length - offset, size);
}
}
if (buf) {
entry->buffers = g_list_prepend (entry->buffers, buf);
return GST_BUFFER_DATA (buf);
} else {
if (entry->requested_size == 0) {
entry->requested_offset = offset;
entry->requested_size = size;
}
return NULL;
}
}
static void
find_suggest (gpointer data, guint probability, GstCaps *caps)
{
gchar *str;
TypeFindEntry *entry = (TypeFindEntry *) data;
str = gst_caps_to_string (caps);
GST_DEBUG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
g_free (str);
if (((gint) probability) > entry->probability) {
entry->probability = probability;
gst_caps_replace (&entry->caps, caps);
}
}
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;
}
}
static void
gst_type_find_element_chain (GstPad *pad, GstData *data)
{
GstTypeFindElement *typefind;
GList *entries;
TypeFindEntry *entry;
GList *walk;
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
if (GST_IS_EVENT (data)) {
gst_type_find_element_handle_event (pad, GST_EVENT (data));
return;
}
switch (typefind->mode) {
case MODE_NORMAL:
gst_pad_push (typefind->src, data);
return;
case MODE_TYPEFIND: {
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
gst_data_unref (data);
if (typefind->possibilities == NULL) {
/* not yet started, get all typefinding functions into our "queue" */
const GList *all_factories = gst_type_find_factory_get_list ();
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
g_list_length ((GList *) all_factories));
while (all_factories) {
entry = g_new0 (TypeFindEntry, 1);
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
entry->self = typefind;
entry->probability = -1;
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
all_factories = g_list_next (all_factories);
}
}
/* call every typefind function once */
walk = entries = typefind->possibilities;
GST_DEBUG_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);
entry->probability = -1;
entry->requested_offset = 0;
entry->requested_size = 0;
gst_type_find_factory_call_function (entry->factory, &find);
free_entry_buffers (entry);
if (entry->probability == -1) {
free_entry (entry);
} else if (entry->probability >= typefind->max_probability) {
/* wooha, got caps */
GstCaps *found_caps = entry->caps;
guint probability = entry->probability;
gst_caps_ref (found_caps);
GST_LOG_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);
}
typefind->possibilities = NULL;
g_list_free (typefind->possibilities);
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], probability, found_caps);
gst_caps_unref (found_caps);
} else {
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
}
}
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, TRUE);
} else if (typefind->possibilities == NULL) {
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
} else {
/* set up typefind element for next iteration */
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
walk = typefind->possibilities;
while (walk) {
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size > 0) {
/* FIXME: need heuristic to find out if we should seek */
GstEvent *event = gst_event_new_seek (entry->requested_offset < 0 ?
GST_SEEK_METHOD_SET : GST_SEEK_METHOD_END, entry->requested_offset);
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
/* done seeking */
break;
} else {
/* impossible to seek */
entry->requested_size = 0;
entry->requested_offset = 0;
}
}
}
/* throw out all entries that can't get more data */
walk = g_list_next (typefind->possibilities);
while (walk) {
GList *cur = walk;
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size == 0) {
free_entry (entry);
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
}
}
if (g_list_next (typefind->possibilities) == NULL) {
entry = (TypeFindEntry *) typefind->possibilities->data;
GST_LOG_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], entry->probability, entry->caps);
free_entry (entry);
g_list_free (typefind->possibilities);
typefind->possibilities = NULL;
stop_typefinding (typefind, TRUE);
}
}
break;
}
default:
g_assert_not_reached ();
return;
}
}
static GstElementStateReturn
gst_type_find_element_change_state (GstElement *element)
{
GstTypeFindElement *typefind;
typefind = GST_TYPE_FIND_ELEMENT (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_PAUSED:
start_typefinding (typefind);
break;
case GST_STATE_PAUSED_TO_READY:
stop_typefinding (typefind, FALSE);
gst_caps_replace (&typefind->caps, NULL);
break;
default:
break;
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
}

View file

@ -0,0 +1,78 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
extern GstElementDetails gst_type_find_element_details;
#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;
GstBufferStore * store;
guint64 stream_length;
gboolean stream_length_available;
GList * possibilities;
};
struct _GstTypeFindElementClass {
GstElementClass parent_class;
/* signals */
void (*have_type) (GstTypeFindElement *element,
guint probability,
GstCaps * caps);
};
GType gst_type_find_element_get_type (void);
G_END_DECLS
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */

View file

@ -0,0 +1,563 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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.
*/
/* 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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gsttypefindelement.h"
#include "gst/gst_private.h"
#include <gst/gsttypefind.h>
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
#define GST_CAT_DEFAULT gst_type_find_element_debug
GstElementDetails gst_type_find_element_details = {
"TypeFind",
"Generic",
"LGPL",
"Finds the media type of a stream",
VERSION,
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
"(C) 2003",
};
/* generic templates */
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_CAPS_ANY
);
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_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 */
};
static void gst_type_find_element_class_init (gpointer g_class,
gpointer class_data);
static void gst_type_find_element_init (GTypeInstance *instance,
gpointer g_class);
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);
static void gst_type_find_element_chain (GstPad * sinkpad,
GstData * data);
static GstElementStateReturn
gst_type_find_element_change_state (GstElement * element);
static GstElementClass *parent_class = NULL;
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
GType
gst_type_find_element_get_type (void)
{
static GType typefind_type = 0;
if (!typefind_type) {
static const GTypeInfo typefind_info = {
sizeof (GstTypeFindElementClass),
NULL,
NULL,
gst_type_find_element_class_init,
NULL,
NULL,
sizeof (GstTypeFindElement),
0,
gst_type_find_element_init,
NULL
};
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstTypeFindElement",
&typefind_info, 0);
}
return typefind_type;
}
static void
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
{
gchar *caps_str;
g_assert (typefind->caps == NULL);
caps_str = gst_caps_to_string (caps);
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
g_free (caps_str);
gst_caps_replace (&typefind->caps, caps);
if (!gst_pad_try_set_caps (typefind->src, caps)) {
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
}
}
static void
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstTypeFindElementClass *typefind_class;
gobject_class = G_OBJECT_CLASS (g_class);
gstelement_class = GST_ELEMENT_CLASS (g_class);
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_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);
g_object_class_install_property (gobject_class, ARG_CAPS,
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
GST_TYPE_CAPS, 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 (g_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);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
typefind_class->have_type = gst_type_find_element_have_type;
}
static void
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
/* sinkpad */
typefind->sink = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
gst_pad_set_chain_function (typefind->sink,
gst_type_find_element_chain);
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
/* srcpad */
typefind->src = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
typefind->caps = NULL;
typefind->min_probability = 1;
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
typefind->store = gst_buffer_store_new ();
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_type_find_element_dispose (GObject *object)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
if (typefind->store) {
g_object_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 void
start_typefinding (GstTypeFindElement *typefind)
{
g_assert (typefind->caps == NULL);
typefind->mode = MODE_TYPEFIND;
}
static void
stop_typefinding (GstTypeFindElement *typefind, gboolean push_cached_buffers)
{
/* stop all typefinding and set mode back to normal */
g_assert (typefind->possibilities == NULL);
typefind->mode = MODE_NORMAL;
if (push_cached_buffers) {
guint size = gst_buffer_store_get_size (typefind->store, 0);
GstBuffer *buffer = gst_buffer_store_get_buffer (typefind->store, 0, size);
if (buffer) {
gst_pad_push (typefind->sink, GST_DATA (buffer));
} else {
size = 0;
}
gst_pad_send_event (GST_PAD_PEER (typefind->sink),
gst_event_new_seek (GST_SEEK_METHOD_SET, size));
}
gst_buffer_store_clear (typefind->store);
}
static void
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
{
gst_pad_event_default (pad, event);
}
typedef struct {
GstTypeFindFactory * factory;
gint probability;
GstCaps * caps;
gint64 requested_offset;
guint requested_size;
GList * buffers;
GstTypeFindElement * self;
} TypeFindEntry;
static void
free_entry_buffers (TypeFindEntry *entry)
{
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
g_list_free (entry->buffers);
entry->buffers = NULL;
}
static void
free_entry (TypeFindEntry *entry)
{
free_entry_buffers (entry);
if (entry->caps)
gst_caps_unref (entry->caps);
g_free (entry);
}
static guint64
find_element_get_length (gpointer data)
{
TypeFindEntry *entry = (TypeFindEntry *) data;
GstTypeFindElement *typefind = entry->self;
GstFormat format = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length ()",
GST_PLUGIN_FEATURE_NAME (entry->factory));
if (!typefind->stream_length_available)
return 0;
if (entry->self->stream_length == 0) {
typefind->stream_length_available = gst_pad_query (entry->self->sink, GST_QUERY_TOTAL,
&format, &entry->self->stream_length);
if (format != GST_FORMAT_BYTES)
typefind->stream_length_available = FALSE;
if (!typefind->stream_length_available)
return 0;
}
return entry->self->stream_length;
}
static guint8 *
find_peek (gpointer data, gint64 offset, guint size)
{
GstBuffer *buf;
TypeFindEntry *entry = (TypeFindEntry *) data;
GST_DEBUG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
if (offset >= 0) {
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
} else {
/* FIXME: can we do this easily without querying length? */
guint64 length = find_element_get_length (data);
if (length == 0) {
buf = NULL;
} else {
buf = gst_buffer_store_get_buffer (entry->self->store, length - offset, size);
}
}
if (buf) {
entry->buffers = g_list_prepend (entry->buffers, buf);
return GST_BUFFER_DATA (buf);
} else {
if (entry->requested_size == 0) {
entry->requested_offset = offset;
entry->requested_size = size;
}
return NULL;
}
}
static void
find_suggest (gpointer data, guint probability, GstCaps *caps)
{
gchar *str;
TypeFindEntry *entry = (TypeFindEntry *) data;
str = gst_caps_to_string (caps);
GST_DEBUG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
g_free (str);
if (((gint) probability) > entry->probability) {
entry->probability = probability;
gst_caps_replace (&entry->caps, caps);
}
}
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;
}
}
static void
gst_type_find_element_chain (GstPad *pad, GstData *data)
{
GstTypeFindElement *typefind;
GList *entries;
TypeFindEntry *entry;
GList *walk;
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
if (GST_IS_EVENT (data)) {
gst_type_find_element_handle_event (pad, GST_EVENT (data));
return;
}
switch (typefind->mode) {
case MODE_NORMAL:
gst_pad_push (typefind->src, data);
return;
case MODE_TYPEFIND: {
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
gst_data_unref (data);
if (typefind->possibilities == NULL) {
/* not yet started, get all typefinding functions into our "queue" */
const GList *all_factories = gst_type_find_factory_get_list ();
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
g_list_length ((GList *) all_factories));
while (all_factories) {
entry = g_new0 (TypeFindEntry, 1);
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
entry->self = typefind;
entry->probability = -1;
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
all_factories = g_list_next (all_factories);
}
}
/* call every typefind function once */
walk = entries = typefind->possibilities;
GST_DEBUG_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);
entry->probability = -1;
entry->requested_offset = 0;
entry->requested_size = 0;
gst_type_find_factory_call_function (entry->factory, &find);
free_entry_buffers (entry);
if (entry->probability == -1) {
free_entry (entry);
} else if (entry->probability >= typefind->max_probability) {
/* wooha, got caps */
GstCaps *found_caps = entry->caps;
guint probability = entry->probability;
gst_caps_ref (found_caps);
GST_LOG_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);
}
typefind->possibilities = NULL;
g_list_free (typefind->possibilities);
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], probability, found_caps);
gst_caps_unref (found_caps);
} else {
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
}
}
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, TRUE);
} else if (typefind->possibilities == NULL) {
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
} else {
/* set up typefind element for next iteration */
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
walk = typefind->possibilities;
while (walk) {
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size > 0) {
/* FIXME: need heuristic to find out if we should seek */
GstEvent *event = gst_event_new_seek (entry->requested_offset < 0 ?
GST_SEEK_METHOD_SET : GST_SEEK_METHOD_END, entry->requested_offset);
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
/* done seeking */
break;
} else {
/* impossible to seek */
entry->requested_size = 0;
entry->requested_offset = 0;
}
}
}
/* throw out all entries that can't get more data */
walk = g_list_next (typefind->possibilities);
while (walk) {
GList *cur = walk;
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size == 0) {
free_entry (entry);
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
}
}
if (g_list_next (typefind->possibilities) == NULL) {
entry = (TypeFindEntry *) typefind->possibilities->data;
GST_LOG_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], entry->probability, entry->caps);
free_entry (entry);
g_list_free (typefind->possibilities);
typefind->possibilities = NULL;
stop_typefinding (typefind, TRUE);
}
}
break;
}
default:
g_assert_not_reached ();
return;
}
}
static GstElementStateReturn
gst_type_find_element_change_state (GstElement *element)
{
GstTypeFindElement *typefind;
typefind = GST_TYPE_FIND_ELEMENT (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_PAUSED:
start_typefinding (typefind);
break;
case GST_STATE_PAUSED_TO_READY:
stop_typefinding (typefind, FALSE);
gst_caps_replace (&typefind->caps, NULL);
break;
default:
break;
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
}

View file

@ -0,0 +1,78 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
extern GstElementDetails gst_type_find_element_details;
#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;
GstBufferStore * store;
guint64 stream_length;
gboolean stream_length_available;
GList * possibilities;
};
struct _GstTypeFindElementClass {
GstElementClass parent_class;
/* signals */
void (*have_type) (GstTypeFindElement *element,
guint probability,
GstCaps * caps);
};
GType gst_type_find_element_get_type (void);
G_END_DECLS
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */

View file

@ -27,9 +27,6 @@
#include "gst.h"
#include "gstqueue.h"
#ifndef GST_DISABLE_TYPEFIND
#include "gsttypefind.h"
#endif /* GST_DISABLE_TYPEFIND */
#ifndef GST_DISABLE_REGISTRY
#include "registries/gstxmlregistry.h"
#endif /* GST_DISABLE_REGISTRY */
@ -461,10 +458,6 @@ gst_register_core_elements (GModule *module, GstPlugin *plugin)
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
factory = gst_element_factory_new ("queue", gst_queue_get_type (), &gst_queue_details);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
#ifndef GST_DISABLE_TYPEFIND
factory = gst_element_factory_new ("typefind", gst_type_find_get_type (), &gst_type_find_details);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
#endif /* GST_DISABLE_TYPEFIND */
return TRUE;
}
@ -510,8 +503,8 @@ init_post (void)
gst_ghost_pad_get_type ();
gst_element_factory_get_type ();
gst_element_get_type ();
gst_type_factory_get_type ();
gst_scheduler_factory_get_type ();
gst_type_find_factory_get_type ();
gst_bin_get_type ();
#ifndef GST_DISABLE_AUTOPLUG
gst_autoplug_factory_get_type ();

View file

@ -41,7 +41,7 @@
#include <gst/gstindex.h>
#include <gst/gstpipeline.h>
#include <gst/gstthread.h>
#include <gst/gsttype.h>
#include <gst/gsttypefind.h>
#include <gst/gstautoplug.h>
#include <gst/gstcaps.h>
#include <gst/gstprops.h>

View file

@ -78,7 +78,6 @@ extern GstDebugCategory *GST_CAT_PLUGIN_LOADING;
extern GstDebugCategory *GST_CAT_PLUGIN_INFO;
extern GstDebugCategory *GST_CAT_PROPERTIES;
extern GstDebugCategory *GST_CAT_THREAD;
extern GstDebugCategory *GST_CAT_TYPES;
extern GstDebugCategory *GST_CAT_XML;
extern GstDebugCategory *GST_CAT_NEGOTIATION;
extern GstDebugCategory *GST_CAT_REFCOUNTING;

View file

@ -301,8 +301,6 @@ gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size)
}
/* ref the real parent */
gst_data_ref (GST_DATA (parent));
/* make sure nobody overwrites data in the parent */
GST_DATA_FLAG_SET (parent, GST_DATA_READONLY);
/* create the new buffer */
buffer = gst_mem_chunk_alloc (chunk);
@ -337,9 +335,12 @@ gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size)
GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
}
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
/* make sure nobody overwrites data as it would overwrite in the parent.
* data in parent cannot be overwritten because we hold a ref */
GST_DATA_FLAG_SET (parent, GST_DATA_READONLY);
return buffer;
}

View file

@ -23,7 +23,6 @@
#include "gst_private.h"
#include "gstcaps.h"
#include "gsttype.h"
#include "gstmemchunk.h"
#include "gstinfo.h"
@ -192,30 +191,6 @@ gst_caps_get_type (void)
{
return _gst_caps_type;
}
static guint16
get_type_for_mime (const gchar *mime)
{
guint16 typeid;
typeid = gst_type_find_by_mime (mime);
if (typeid == 0) {
GstTypeDefinition definition;
GstTypeFactory *factory;
definition.name = "capstype";
definition.mime = g_strdup (mime);
definition.exts = NULL;
definition.typefindfunc = NULL;
factory = gst_type_factory_new (&definition);
typeid = gst_type_register (factory);
g_free (definition.mime);
}
return typeid;
}
/**
* gst_caps_new:
* @name: the name of this capability
@ -231,9 +206,8 @@ gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
{
g_return_val_if_fail (mime != NULL, NULL);
return gst_caps_new_id (name, get_type_for_mime (mime), props);
return gst_caps_new_id (name, g_quark_from_string (mime), props);
}
/**
* gst_caps_new_id:
* @name: the name of this capability
@ -245,7 +219,7 @@ gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
* Returns: a new capability
*/
GstCaps*
gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props)
gst_caps_new_id (const gchar *name, const GQuark id, GstProps *props)
{
GstCaps *caps;
@ -584,7 +558,6 @@ gst_caps_set_name (GstCaps *caps, const gchar *name)
g_free (caps->name);
caps->name = g_strdup (name);
}
/**
* gst_caps_get_mime:
* @caps: the caps to get the mime type from
@ -596,18 +569,10 @@ gst_caps_set_name (GstCaps *caps, const gchar *name)
const gchar*
gst_caps_get_mime (GstCaps *caps)
{
GstType *type;
g_return_val_if_fail (caps != NULL, NULL);
type = gst_type_find_by_id (caps->id);
if (type)
return type->mime;
else
return "unknown/unknown";
return g_quark_to_string (caps->id);
}
/**
* gst_caps_set_mime:
* @caps: the caps to set the mime type to
@ -621,40 +586,8 @@ gst_caps_set_mime (GstCaps *caps, const gchar *mime)
g_return_if_fail (caps != NULL);
g_return_if_fail (mime != NULL);
caps->id = get_type_for_mime (mime);
caps->id = g_quark_from_string (mime);
}
/**
* gst_caps_get_type_id:
* @caps: the caps to get the type id from
*
* Get the type id of the caps.
*
* Returns: the type id of the caps
*/
guint16
gst_caps_get_type_id (GstCaps *caps)
{
g_return_val_if_fail (caps != NULL, 0);
return caps->id;
}
/**
* gst_caps_set_type_id:
* @caps: the caps to set the type id to
* @type_id: the type id to set
*
* Set the type id of the caps.
*/
void
gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
{
g_return_if_fail (caps != NULL);
caps->id = type_id;
}
/**
* gst_caps_set_props:
* @caps: the caps to attach the properties to
@ -880,8 +813,8 @@ gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
{
if (fromcaps->id != tocaps->id) {
GST_CAT_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)",
gst_type_find_by_id (fromcaps->id)->mime,
gst_type_find_by_id (tocaps->id)->mime);
gst_caps_get_mime (fromcaps),
gst_caps_get_mime (tocaps));
return FALSE;
}
@ -963,8 +896,8 @@ gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
if (caps1->id != caps2->id) {
GST_CAT_DEBUG (GST_CAT_CAPS, "mime types differ (%s to %s)",
gst_type_find_by_id (caps1->id)->mime,
gst_type_find_by_id (caps2->id)->mime);
gst_caps_get_mime (caps1),
gst_caps_get_mime (caps2));
return NULL;
}
@ -1127,7 +1060,7 @@ gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
xmlNewChild (subtree, NULL, "name", caps->name);
xmlNewChild (subtree, NULL, "type", gst_type_find_by_id (caps->id)->mime);
xmlNewChild (subtree, NULL, "type", gst_caps_get_mime (caps));
if (caps->properties) {
subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
@ -1175,7 +1108,7 @@ gst_caps_load_thyself (xmlNodePtr parent)
}
if (!strcmp (subfield->name, "type")) {
content = xmlNodeGetContent (subfield);
caps->id = get_type_for_mime (content);
caps->id = g_quark_from_string (content);
g_free (content);
}
else if (!strcmp (subfield->name, "properties")) {

View file

@ -63,7 +63,7 @@ typedef enum {
struct _GstCaps {
/* --- public --- */
gchar *name; /* the name of this caps */
guint16 id; /* type id (major type) representing
GQuark id; /* type id (major type) representing
the mime type, it's stored as a GQuark
for speed/space reasons */
@ -126,7 +126,7 @@ void _gst_caps_initialize (void);
/* creating new caps */
GType gst_caps_get_type (void);
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
GstCaps* gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props);
GstCaps* gst_caps_new_id (const gchar *name, const GQuark id, GstProps *props);
GstCaps* gst_caps_get_any (void);
/* replace pointer to caps, doing proper refcounting */
void gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps);
@ -151,9 +151,6 @@ void gst_caps_set_name (GstCaps *caps, const gchar *name);
const gchar* gst_caps_get_mime (GstCaps *caps);
void gst_caps_set_mime (GstCaps *caps, const gchar *mime);
guint16 gst_caps_get_type_id (GstCaps *caps);
void gst_caps_set_type_id (GstCaps *caps, guint16 type_id);
GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props);
GstProps* gst_caps_get_props (GstCaps *caps);

View file

@ -10,7 +10,6 @@
#define GST_DISABLE_LOADSAVE_REGISTRY 1
#define GST_DISABLE_GST_DEBUG 1
#define GST_DISABLE_LOADSAVE 1
#define GST_DISABLE_TYPEFIND 1
#define GST_DISABLE_AUTOPLUG 1
#define GST_DISABLE_PARSE 1
#define GST_DISABLE_TRACE 1
@ -31,9 +30,6 @@
/* DOES NOT WORK */
@GST_DISABLE_LOADSAVE_DEFINE@
/* DOES NOT WORK */
@GST_DISABLE_TYPEFIND_DEFINE@
/* DOES NOT WORK */
@GST_DISABLE_AUTOPLUG_DEFINE@

View file

@ -9,4 +9,6 @@ VOID:OBJECT,POINTER
VOID:OBJECT,STRING
VOID:INT,INT
VOID:INT64
VOID:UINT,BOXED
BOOLEAN:VOID
BOOLEAN:POINTER

View file

@ -25,7 +25,6 @@
#include "gstpad.h"
#include "gstutils.h"
#include "gstelement.h"
#include "gsttype.h"
#include "gstbin.h"
#include "gstscheduler.h"
#include "gstevent.h"

View file

@ -27,6 +27,8 @@
#include "gstregistry.h"
#include "gstinfo.h"
#include <string.h>
static void gst_plugin_feature_class_init (GstPluginFeatureClass *klass);
static void gst_plugin_feature_init (GstPluginFeature *feature);
@ -136,7 +138,6 @@ gst_plugin_feature_type_name_filter (GstPluginFeature *feature,
return ((data->type == 0 || data->type == G_OBJECT_TYPE (feature)) &&
(data->name == NULL || !strcmp (data->name, GST_PLUGIN_FEATURE_NAME (feature))));
}
/**
* gst_plugin_feature_set_rank:
* @feature: feature to rank
@ -153,4 +154,25 @@ gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank)
feature->rank = rank;
}
/**
* gst_plugin_feature_set_rank:
* @feature: a feature
* @name: the name to set
*
* Sets the name of a plugin feature. The name uniquely identifies a feature
* within all features of the same type. Renaming a plugin feature is not
* allowed.
*/
void
gst_plugin_feature_set_name (GstPluginFeature *feature, const gchar *name)
{
g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
g_return_if_fail (name != NULL);
if (feature->name) {
g_return_if_fail (strcmp (feature->name, name) == 0);
} else {
feature->name = g_strdup (name);
}
}

View file

@ -80,6 +80,7 @@ gboolean gst_plugin_feature_type_name_filter (GstPluginFeature *feature,
GstTypeNameData *data);
void gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank);
void gst_plugin_feature_set_name (GstPluginFeature *feature, const gchar *name);
G_END_DECLS

View file

@ -1,8 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.c:
* gsttypefind.h: typefinding subsystem
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -20,234 +19,304 @@
* Boston, MA 02111-1307, USA.
*/
#include "gst_private.h"
#include "gsttype.h"
#include "gstinfo.h"
#include "gsttypefind.h"
#include "gstregistrypool.h"
GstElementDetails gst_type_find_details = {
"TypeFind",
"Generic",
"LGPL",
"Finds the media type of a stream",
VERSION,
"Erik Walthinsen <omega@cse.ogi.edu>,"
"Wim Taymans <wim.taymans@chello.be>",
"(C) 1999",
};
GST_DEBUG_CATEGORY_STATIC (gst_type_find_debug);
#define GST_CAT_DEFAULT gst_type_find_debug
/* generic templates */
GST_PAD_TEMPLATE_FACTORY (type_find_sink_factory,
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
NULL
);
/* TypeFind signals and args */
/* GstTypeFind flags */
enum {
HAVE_TYPE,
LAST_SIGNAL
FLAG_OFFSET = (1 << 0),
FLAG_SIZE = (1 << 1),
FLAG_CAPS = (1 << 2),
FLAG_EXTENSIONS = (1 << 3)
};
enum {
ARG_0,
ARG_CAPS,
};
static void gst_type_find_factory_class_init (gpointer g_class,
gpointer class_data);
static void gst_type_find_factory_init (GTypeInstance * instance,
gpointer g_class);
static void gst_type_find_factory_dispose (GObject * object);
static void gst_type_find_factory_unload_thyself (GstPluginFeature * feature);
static void gst_type_find_class_init (GstTypeFindClass *klass);
static void gst_type_find_init (GstTypeFind *typefind);
static void gst_type_find_load_plugin (GstTypeFind * find,
gpointer data);
static void gst_type_find_set_property (GObject *object, guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gst_type_find_get_property (GObject *object, guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gst_type_find_loopfunc (GstElement *element);
static GstElementStateReturn
gst_type_find_change_state (GstElement *element);
static GstElementClass *parent_class = NULL;
static guint gst_type_find_signals[LAST_SIGNAL] = { 0 };
static GstPluginFeatureClass *parent_class = NULL;
GType
gst_type_find_get_type (void)
gst_type_find_factory_get_type (void)
{
static GType typefind_type = 0;
if (!typefind_type) {
static const GTypeInfo typefind_info = {
sizeof(GstTypeFindClass),
sizeof (GstTypeFindFactoryClass),
NULL,
NULL,
(GClassInitFunc)gst_type_find_class_init,
gst_type_find_factory_class_init,
NULL,
NULL,
sizeof(GstTypeFind),
sizeof (GstTypeFindFactory),
0,
(GInstanceInitFunc)gst_type_find_init,
gst_type_find_factory_init,
NULL
};
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstTypeFind",
typefind_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
"GstTypeFindFactory",
&typefind_info, 0);
GST_DEBUG_CATEGORY_INIT (gst_type_find_debug, "GST_TYPEFIND",
GST_DEBUG_FG_GREEN, "typefinding subsystem");
}
return typefind_type;
}
static void
gst_type_find_class_init (GstTypeFindClass *klass)
gst_type_find_factory_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CAPS,
g_param_spec_pointer ("caps", "Caps", "Found capabilities", G_PARAM_READABLE));
gst_type_find_signals[HAVE_TYPE] =
g_signal_new ("have_type", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstTypeFindClass, have_type), NULL, NULL,
g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
G_TYPE_POINTER);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_get_property);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_change_state);
GstPluginFeatureClass *gstpluginfeature_class = GST_PLUGIN_FEATURE_CLASS (g_class);
GObjectClass *object_class = G_OBJECT_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_class);
object_class->dispose = gst_type_find_factory_dispose;
gstpluginfeature_class->unload_thyself = GST_DEBUG_FUNCPTR (gst_type_find_factory_unload_thyself);
}
static void
gst_type_find_init (GstTypeFind *typefind)
gst_type_find_factory_init (GTypeInstance *instance, gpointer g_class)
{
typefind->sinkpad = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_sink_factory), "sink");
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sinkpad);
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (instance);
gst_element_set_loop_function (GST_ELEMENT (typefind),
gst_type_find_loopfunc);
typefind->caps = NULL;
factory->user_data = factory;
factory->function = gst_type_find_load_plugin;
}
static void
gst_type_find_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
gst_type_find_factory_dispose (GObject *object)
{
GstTypeFind *typefind;
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (object);
g_return_if_fail (GST_IS_TYPE_FIND (object));
typefind = GST_TYPE_FIND (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
if (factory->caps) {
gst_caps_unref (factory->caps);
factory->caps = NULL;
}
if (factory->extensions) {
g_strfreev (factory->extensions);
factory->extensions = NULL;
}
}
static void
gst_type_find_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
gst_type_find_factory_unload_thyself (GstPluginFeature *feature)
{
GstTypeFind *typefind;
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
g_return_if_fail (GST_IS_TYPE_FIND (object));
typefind = GST_TYPE_FIND (object);
switch (prop_id) {
case ARG_CAPS:
g_value_set_pointer (value, typefind->caps);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
factory->function = gst_type_find_load_plugin;
factory->user_data = factory;
}
static void
gst_type_find_loopfunc (GstElement *element)
gst_type_find_load_plugin (GstTypeFind *find, gpointer data)
{
GstTypeFind *typefind;
const GList *type_list;
GstType *type;
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (data);
typefind = GST_TYPE_FIND (element);
GST_DEBUG ("Started typefinding loop in '%s'",
GST_OBJECT_NAME (typefind));
type_list = gst_type_get_list ();
while (type_list) {
GSList *factories;
type = (GstType *) type_list->data;
factories = type->factories;
while (factories) {
GstTypeFactory *factory = GST_TYPE_FACTORY (factories->data);
GstTypeFindFunc typefindfunc = (GstTypeFindFunc) factory->typefindfunc;
GstCaps *caps;
GST_CAT_DEBUG (GST_CAT_TYPES, "try type (%p) :%d \"%s\" %p",
factory, type->id, type->mime, typefindfunc);
if (typefindfunc && (caps = typefindfunc (typefind->bs, factory))) {
GST_CAT_DEBUG (GST_CAT_TYPES, "found type: %d \"%s\" \"%s\"",
caps->id, type->mime, gst_caps_get_name (caps));
gst_caps_replace (&typefind->caps, caps);
if (gst_pad_try_set_caps (typefind->sinkpad, caps) <= 0) {
g_warning ("typefind: found type but peer didn't accept it");
}
gst_object_ref (GST_OBJECT (typefind));
g_signal_emit (G_OBJECT (typefind), gst_type_find_signals[HAVE_TYPE],
0, typefind->caps);
gst_object_unref (GST_OBJECT (typefind));
return;
}
factories = g_slist_next (factories);
GST_DEBUG_OBJECT (factory, "need to load typefind function %s", GST_PLUGIN_FEATURE_NAME (factory));
if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
if (factory->function == gst_type_find_load_plugin) {
/* looks like we didn't get a real typefind function */
g_warning ("could not load valid typefind function for feature '%s'\n", GST_PLUGIN_FEATURE_NAME (factory));
} else {
g_assert (factory->function);
gst_type_find_factory_call_function (factory, find);
}
type_list = g_list_next (type_list);
}
/* if we get here, nothing worked... :'(. */
gst_element_error (GST_ELEMENT (typefind),
"media type could not be detected");
}
static GstElementStateReturn
gst_type_find_change_state (GstElement *element)
/**
* gst_type_find_factory_get_list:
*
* Gets the list of all registered typefind factories. You must free the
* list using g_list_free.
*
* Returns: the list of all registered typefind factories
*/
GList *
gst_type_find_factory_get_list (void)
{
GstTypeFind *typefind;
GstElementStateReturn ret;
typefind = GST_TYPE_FIND (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_PAUSED:
typefind->bs = gst_bytestream_new (typefind->sinkpad);
break;
case GST_STATE_PAUSED_TO_READY:
gst_bytestream_destroy (typefind->bs);
gst_caps_replace (&typefind->caps, NULL);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
return ret;
return gst_registry_pool_feature_list (GST_TYPE_TYPE_FIND_FACTORY);
}
/**
* gst_type_find_factory_get_caps:
* @factory: a factory
*
* Gets the caps associated with a typefind factory.
*
* Returns: the #GstCaps associated with this factory
*/
GstCaps *
gst_type_find_factory_get_caps (const GstTypeFindFactory *factory)
{
g_return_val_if_fail (GST_IS_TYPE_FIND_FACTORY (factory), NULL);
return factory->caps;
}
/**
* gst_type_find_factory_get_extensions:
* @factory: a factory
*
* Gets the extensions associated with a typefind factory. The returned
* array should not be changed. If you need to change stuff in it, you should
* copy it using g_stdupv().
*
* Returns: a NULL-terminated array of extensions associated with this factory
*/
gchar **
gst_type_find_factory_get_extensions (const GstTypeFindFactory *factory)
{
g_return_val_if_fail (GST_IS_TYPE_FIND_FACTORY (factory), NULL);
return factory->extensions;
}
/**
* gst_type_find_factory_call_function:
* @factory: a factory
* @find: a properly setup #GstTypeFind entry. The get_data and suggest_type
* members must be set.
*
* Calls the typefinding function associated with this factory.
*/
void
gst_type_find_factory_call_function (const GstTypeFindFactory *factory, GstTypeFind *find)
{
g_return_if_fail (GST_IS_TYPE_FIND_FACTORY (factory));
g_return_if_fail (find != NULL);
g_return_if_fail (find->peek != NULL);
g_return_if_fail (find->suggest != NULL);
/* should never happen */
g_assert (factory->function != NULL);
factory->function (find, factory->user_data);
}
/**
* gst_type_find_factory_register:
* @plugin: the GstPlugin to register with
* @name: the name for registering
* @rank: rank (or importance) of this typefind function
* @func: the function to use for typefinding
* @extensions: optional extensions that could belong to this type
* @possible_caps: optionally the caps that could be returned when typefinding succeeds
* @data: optional user data. This user data must be available until the plugin
* is unloaded.
*
* Registers a new typefind function to be used for typefinding. After
* registering this function will be available for typefinding.
* This function is typically called during an element's plugin initialization.
*
* Returns: TRUE on success, FALSE otherwise
*/
void
gst_type_find_factory_register (GstPlugin *plugin, const gchar *name, guint rank,
GstTypeFindFunction func, gchar **extensions, GstCaps *possible_caps,
gpointer data)
{
GstTypeFindFactory *factory;
g_return_if_fail (plugin != NULL);
g_return_if_fail (name != NULL);
g_return_if_fail (func != NULL);
GST_INFO ("registering typefind function for %s", name);
factory = GST_TYPE_FIND_FACTORY (gst_registry_pool_find_feature (name, GST_TYPE_TYPE_FIND_FACTORY));
if (!factory) {
factory = g_object_new (GST_TYPE_TYPE_FIND_FACTORY, NULL);
GST_DEBUG_OBJECT (factory, "using new typefind factory for %s", name);
g_assert (GST_IS_TYPE_FIND_FACTORY (factory));
gst_plugin_feature_set_name (GST_PLUGIN_FEATURE (factory), name);
} else {
GST_DEBUG_OBJECT (factory, "using old typefind factory for %s", name);
}
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), rank);
if (factory->extensions)
g_strfreev (factory->extensions);
factory->extensions = g_strdupv (extensions);
gst_caps_replace (&factory->caps, possible_caps);
factory->function = func;
factory->user_data = data;
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
}
/*** typefind function interface **********************************************/
/*
* gst_type_find_peek:
* @find: the find object the function was called with
* @offset: the offset
* @size: the number of bytes to return
*
* Returns size bytes of the stream to identify beginning at offset. If offset
* is a positive number, the offset is relative to the beginning of the stream,
* if offset is a negative number the offset is relative to the end of the
* stream. The returned memory is valid until the typefinding function returns
* and must not be freed.
* If NULL is returned, that data is not available.
*
* Returns: the requested data or NULL if that data is not available.
*/
guint8 *
gst_type_find_peek (GstTypeFind *find, gint64 offset, guint size)
{
g_return_val_if_fail (find->peek != NULL, NULL);
return find->peek (find->data, offset, size);
}
/*
* gst_type_find_suggest:
* @find: the find object the function was called with
* @probability: the probability in percent that the suggestion is right
* @caps: the fixed caps to suggest
*
* If a typefind function calls this function it suggests the caps with the
* given probability. A typefind function may supply different suggestions
* in one call.
* It is up to the caller of the typefind function to interpret these values.
* <note>A typefind function not suggesting Caps during one call is thought
* to have no chance to identify the data. If there is even the slightest
* possibility that this data may still be identified by your function once
* more data is available you must call this function - preferrably with a
* probability of 0.</note>
*/
void
gst_type_find_suggest (GstTypeFind *find, guint probability, GstCaps *caps)
{
g_return_if_fail (find->suggest != NULL);
g_return_if_fail (probability <= 100);
g_return_if_fail (caps != NULL);
g_return_if_fail (GST_CAPS_IS_FIXED (caps));
gst_caps_ref (caps);
gst_caps_sink (caps);
find->suggest (find->data, probability, caps);
gst_caps_unref (caps);
}
/**
* gst_type_find_get_length:
* @find: the find object the function was called with
*
* Get the length of the data stream.
*
* Returns: the length of the data stream or 0 if it is not available.
*/
guint64
gst_type_find_get_length (GstTypeFind *find)
{
if (find->get_length == NULL)
return 0;
return find->get_length(find->data);
}

View file

@ -1,8 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.h:
* gsttypefind.h: typefinding subsystem
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -24,51 +23,103 @@
#ifndef __GST_TYPE_FIND_H__
#define __GST_TYPE_FIND_H__
#ifndef GST_DISABLE_TYPE_FIND
#include <gst/gstelement.h>
#include <gst/gstbytestream.h>
#include <gst/gstbuffer.h>
#include <gst/gstcaps.h>
#include <gst/gstplugin.h>
#include <gst/gstpluginfeature.h>
#include <gst/gsttypes.h>
G_BEGIN_DECLS
extern GstElementDetails gst_type_find_details;
#define GST_TYPE_TYPE_FIND_FACTORY (gst_type_find_factory_get_type())
#define GST_TYPE_FIND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND_FACTORY, GstTypeFindFactory))
#define GST_IS_TYPE_FIND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND_FACTORY))
#define GST_TYPE_FIND_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND_FACTORY, GstTypeFindFactoryClass))
#define GST_IS_TYPE_FIND_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND_FACTORY))
#define GST_TYPE_FIND_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND_FACTORY, GstTypeFindFactoryClass))
#define GST_TYPE_TYPE_FIND (gst_type_find_get_type ())
#define GST_TYPE_FIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND, GstTypeFind))
#define GST_IS_TYPE_FIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND))
#define GST_TYPE_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND, GstTypeFindClass))
#define GST_IS_TYPE_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND))
#define GST_TYPE_FIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND, GstTypeFindClass))
typedef struct _GstTypeFind GstTypeFind;
typedef struct _GstTypeFindFactory GstTypeFindFactory;
typedef struct _GstTypeFindFactoryClass GstTypeFindFactoryClass;
typedef struct _GstTypeFind GstTypeFind;
typedef struct _GstTypeFindClass GstTypeFindClass;
typedef void (* GstTypeFindFunction) (GstTypeFind *info, gpointer data);
enum {
GST_TYPE_FIND_NO_IDEA = 0,
GST_TYPE_FIND_MINIMUM = 1,
GST_TYPE_FIND_POSSIBLE = 50,
GST_TYPE_FIND_LIKELY = 80,
GST_TYPE_FIND_NEARLY_CERTAIN = 99,
GST_TYPE_FIND_MAXIMUM = 100,
} GstTypeFindProbability;
struct _GstTypeFind {
GstElement element;
/* private to the caller of the typefind function */
guint8 * (* peek) (gpointer data,
gint64 offset,
guint size);
void (* suggest) (gpointer data,
guint probability,
GstCaps * caps);
gpointer data;
/* optional */
guint64 (* get_length) (gpointer data);
GstPad *sinkpad;
GstByteStream *bs;
GstCaps *caps;
GST_OBJECT_PADDING
GST_STRUCT_PADDING
};
struct _GstTypeFindClass {
GstElementClass parent_class;
/* signals */
void (*have_type) (GstElement *element,
GstCaps *caps);
struct _GstTypeFindFactory {
GstPluginFeature feature;
/* <private> */
GstTypeFindFunction function;
gchar ** extensions;
GstCaps * caps; /* FIXME: not yet saved in registry */
gpointer user_data;
GST_OBJECT_PADDING
};
struct _GstTypeFindFactoryClass {
GstPluginFeatureClass parent;
/* <private> */
GST_CLASS_PADDING
};
GType gst_type_find_get_type (void);
/* typefind function interface */
guint8 * gst_type_find_peek (GstTypeFind * find,
gint64 offset,
guint size);
void gst_type_find_suggest (GstTypeFind * find,
guint probability,
GstCaps * caps);
guint64 gst_type_find_get_length (GstTypeFind * find);
/* registration interface */
void gst_type_find_factory_register (GstPlugin * plugin,
const gchar * name,
guint rank,
GstTypeFindFunction func,
gchar ** extensions,
GstCaps * possible_caps,
gpointer data);
/* typefinding interface */
GType gst_type_find_factory_get_type (void);
GList * gst_type_find_factory_get_list (void);
gchar ** gst_type_find_factory_get_extensions (const GstTypeFindFactory *factory);
GstCaps * gst_type_find_factory_get_caps (const GstTypeFindFactory *factory);
void gst_type_find_factory_call_function (const GstTypeFindFactory *factory,
GstTypeFind *find);
G_END_DECLS
#endif /* GST_DISABLE_TYPE_FIND */
#endif /* __GST_TYPE_FIND_H__ */

View file

@ -265,7 +265,6 @@ gst_util_set_object_arg (GObject * object, const gchar * name, const gchar * val
*/
#include "gstpad.h"
#include "gsttype.h"
#include "gstprops.h"
static void
@ -399,14 +398,11 @@ gst_print_pad_caps (GString * buf, gint indent, GstPad * pad)
gint capx = 0;
while (caps) {
GstType *type;
string_append_indent (buf, indent);
g_string_append_printf (buf, "Cap[%d]: %s\n", capx++, caps->name);
type = gst_type_find_by_id (caps->id);
string_append_indent (buf, indent + 2);
g_string_append_printf (buf, "MIME type: %s\n", type->mime ? type->mime : "unknown/unknown");
g_string_append_printf (buf, "MIME type: %s\n", gst_caps_get_mime (caps));
if (caps->properties)
gst_print_props (buf, indent + 4, caps->properties->properties, TRUE);

View file

@ -34,7 +34,7 @@
#include <gst/gst_private.h>
#include <gst/gstelement.h>
#include <gst/gsttype.h>
#include <gst/gsttypefind.h>
#include <gst/gstscheduler.h>
#include <gst/gstautoplug.h>
#include <gst/gsturi.h>
@ -712,19 +712,42 @@ gst_xml_registry_parse_element_factory (GMarkupParseContext *context, const gcha
}
static gboolean
gst_xml_registry_parse_type_factory (GMarkupParseContext *context, const gchar *tag, const gchar *text,
gsize text_len, GstXMLRegistry *registry, GError **error)
gst_xml_registry_parse_type_find_factory (GMarkupParseContext *context, const gchar *tag, const gchar *text,
gsize text_len, GstXMLRegistry *registry, GError **error)
{
GstTypeFactory *factory = GST_TYPE_FACTORY (registry->current_feature);
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (registry->current_feature);
if (!strcmp (tag, "name")) {
registry->current_feature->name = g_strndup (text, text_len);
}
else if (!strcmp (tag, "mime")) {
factory->mime = g_strndup (text, text_len);
else if (!strcmp(tag, "rank")) {
glong rank;
gchar *ret;
rank = strtol (text, &ret, 0);
if (ret == text + text_len) {
gst_element_factory_set_rank (factory, rank);
}
}
else if (!strcmp(tag, "extensions")) {
factory->exts = g_strndup (text, text_len);
/* FIXME!!
else if (!strcmp (tag, "caps")) {
factory->caps = g_strndup (text, text_len);
}*/
else if (!strcmp(tag, "extension")) {
gchar **new;
gchar **old = factory->extensions;
gint i = 0;
/* expensive, but cycles are cheap... */
if (old)
while (old[i]) i++;
new = g_new0 (gchar *, i + 2);
new[i] = g_strndup (text, text_len);
while (i > 0) {
i--;
new[i] = old[i];
}
g_free (old);
factory->extensions = new;
}
return TRUE;
@ -905,8 +928,8 @@ gst_xml_registry_start_element (GMarkupParseContext *context,
xmlregistry->parser = gst_xml_registry_parse_element_factory;
break;
}
else if (GST_IS_TYPE_FACTORY (feature)) {
xmlregistry->parser = gst_xml_registry_parse_type_factory;
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
xmlregistry->parser = gst_xml_registry_parse_type_find_factory;
}
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
xmlregistry->parser = gst_xml_registry_parse_scheduler_factory;
@ -1087,20 +1110,11 @@ gst_xml_registry_end_element (GMarkupParseContext *context,
break;
case GST_XML_REGISTRY_FEATURE:
if (!strcmp (element_name, "feature")) {
if (GST_IS_TYPE_FACTORY (xmlregistry->current_feature)) {
GstTypeFactory *factory = GST_TYPE_FACTORY (xmlregistry->current_feature);
gst_type_register (factory);
}
xmlregistry->state = GST_XML_REGISTRY_PLUGIN;
xmlregistry->parser = gst_xml_registry_parse_plugin;
gst_plugin_add_feature (xmlregistry->current_plugin, xmlregistry->current_feature);
xmlregistry->current_feature = NULL;
}
else if (!strcmp (element_name, "typefind")) {
GstTypeFactory *factory = GST_TYPE_FACTORY (xmlregistry->current_feature);
factory->typefindfunc = gst_type_type_find_dummy;
}
break;
case GST_XML_REGISTRY_PADTEMPLATE:
if (!strcmp (element_name, "padtemplate")) {
@ -1270,12 +1284,19 @@ gst_xml_registry_paths_text (GMarkupParseContext *context, const gchar *text,
#define PUT_ESCAPED(tag,value) \
G_STMT_START{ \
const gchar *toconv = value; \
if (value) { \
if (toconv) { \
gchar *v = g_markup_escape_text (toconv, strlen (toconv)); \
CLASS (xmlregistry)->save_func (xmlregistry, "<%s>%s</%s>\n", tag, v, tag); \
g_free (v); \
} \
}G_STMT_END
#define PUT_ESCAPED_INT(tag,value) \
G_STMT_START{ \
gchar *save = g_strdup_printf ("%ld", (glong) value); \
CLASS (xmlregistry)->save_func (xmlregistry, "<%s>%s</%s>\n", tag, save, tag); \
g_free (save); \
}G_STMT_END
static gboolean
gst_xml_registry_save_props_func (GstPropsEntry *entry,
@ -1381,7 +1402,7 @@ gst_xml_registry_save_caps (GstXMLRegistry *xmlregistry, GstCaps *caps)
while (caps) {
CLASS (xmlregistry)->save_func (xmlregistry, "<capscomp>\n");
PUT_ESCAPED ("name", caps->name);
PUT_ESCAPED ("type", gst_type_find_by_id (caps->id)->mime);
PUT_ESCAPED ("type", gst_caps_get_mime (caps));
if (caps->properties) {
CLASS (xmlregistry)->save_func (xmlregistry, "<properties>\n");
@ -1460,13 +1481,18 @@ gst_xml_registry_save_feature (GstXMLRegistry *xmlregistry, GstPluginFeature *fe
templates = g_list_next (templates);
}
}
else if (GST_IS_TYPE_FACTORY (feature)) {
GstTypeFactory *factory = GST_TYPE_FACTORY (feature);
PUT_ESCAPED ("mime", factory->mime);
PUT_ESCAPED ("extensions", factory->exts);
if (factory->typefindfunc) {
CLASS (xmlregistry)->save_func (xmlregistry, "<typefind/>\n");
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
gint i = 0;
/* FIXME
if (factory->caps) {
CLASS (xmlregistry)->save_func (xmlregistry, "<caps>\n");
gst_xml_registry_save_caps (xmlregistry, factory->caps);
CLASS (xmlregistry)->save_func (xmlregistry, "</caps>\n");
} */
while (factory->extensions[i]) {
PUT_ESCAPED ("extension", factory->extensions[i]);
i++;
}
}
else if (GST_IS_SCHEDULER_FACTORY (feature)) {

View file

@ -1,7 +0,0 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

View file

@ -1,8 +0,0 @@
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
plugin_LTLIBRARIES = libgsttypes.la
libgsttypes_la_SOURCES = gsttypes.c
libgsttypes_la_CFLAGS = $(GST_CFLAGS)
libgsttypes_la_LIBADD =
libgsttypes_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)

View file

@ -1,55 +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>
#include <string.h>
GstTypeDefinition _definitions[] = {
{ "gsttypes_audio/raw", "audio/raw", ".raw", NULL },
{ "gsttypes_video/raw", "video/raw", ".raw", NULL },
{ NULL, NULL, NULL, NULL },
};
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
gint i = 0;
while (_definitions[i].name) {
GstTypeFactory *factory;
factory = gst_type_factory_new (&_definitions[i]);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
GST_DEBUG ( "added factory #%d '%s'", i, _definitions[i].name);
i++;
}
/*gst_info ("gsttypes: loaded %d standard types\n",i);*/
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gsttypes",
plugin_init
};

View file

@ -1,3 +1,3 @@
SUBDIRS = control getbits
SUBDIRS = control getbits bytestream
DIST_SUBDIRS = control getbits
DIST_SUBDIRS = control getbits bytestream

View file

@ -0,0 +1,10 @@
librarydir = $(libdir)/gstreamer-@GST_MAJORMINOR@
library_LTLIBRARIES = libgstbytestream.la
libgstbytestreamincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst
libgstbytestreaminclude_HEADERS = bytestream.h
libgstbytestream_la_SOURCES = bytestream.c
libgstbytestream_la_CFLAGS = $(GST_CFLAGS)
libgstbytestream_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)

View file

@ -28,7 +28,9 @@
#include <stdlib.h>
#include <gst/gstinfo.h>
#include <gst/gstbytestream.h>
#include <gst/gstplugin.h>
#include <gst/gstversion.h>
#include "bytestream.h"
GST_DEBUG_CATEGORY_STATIC(debug_bs);
#define GST_CAT_DEFAULT debug_bs
@ -744,3 +746,17 @@ gst_bytestream_print_status (GstByteStream * bs)
GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
}
}
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
gst_plugin_set_longname (plugin, "GstByteStream: a byte-oriented layer on top of buffer-passing");
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gstbytestream",
plugin_init
};

View file

@ -1,40 +1,51 @@
# FIXME:
# need to get gstbufferstore.[ch] into its own lib, preferrably
# libs/gst/buifferstore
# This requires building libs/gst before this dir, which we currently don't
# do.
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
plugin_LTLIBRARIES = libgstelements.la
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
libgstelements_la_SOURCES = \
gstaggregator.c \
gstbufferstore.c \
gstelements.c \
gstfakesrc.c \
gstidentity.c \
gstfakesink.c \
gstfilesrc.c \
gstfakesrc.c \
gstfilesink.c \
gstfdsrc.c \
gstfilesrc.c \
gstfdsink.c \
gstfdsrc.c \
gstidentity.c \
gstmd5sink.c \
gstmultidisksrc.c \
gstpipefilter.c \
gsttee.c \
gstaggregator.c \
gstshaper.c \
gststatistics.c \
gstmd5sink.c
gsttee.c \
gsttypefindelement.c
libgstelements_la_CFLAGS = $(GST_CFLAGS)
libgstelements_la_LIBADD =
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = \
gstfakesrc.h \
gstidentity.h \
gstfakesink.h \
gstfilesink.h \
gstfdsrc.h \
gstmultidisksrc.h \
gstfdsink.h \
gstpipefilter.h \
gsttee.h \
gstaggregator.h \
gstshaper.h \
gststatistics.h \
gstbufferstore.h \
gstfakesink.h \
gstfakesrc.h \
gstfdsink.h \
gstfdsrc.h \
gstfilesink.h \
gstfilesrc.h \
gstmd5sink.h
gstidentity.h \
gstmd5sink.h \
gstmultidisksrc.h \
gstpipefilter.h \
gstshaper.h \
gststatistics.h \
gsttee.h \
gsttypefindelement.h

View file

@ -0,0 +1,427 @@
/* 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 <string.h>
GST_DEBUG_CATEGORY (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_class_init (gpointer g_class,
gpointer class_data);
static void gst_buffer_store_init (GTypeInstance * instance,
gpointer g_class);
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 GObjectClass *parent_class = NULL;
static guint gst_buffer_store_signals[LAST_SIGNAL] = { 0 };
GType
gst_buffer_store_get_type (void)
{
static GType store_type = 0;
if (!store_type) {
static const GTypeInfo store_info = {
sizeof (GstBufferStoreClass),
NULL,
NULL,
gst_buffer_store_class_init,
NULL,
NULL,
sizeof (GstBufferStore),
0,
gst_buffer_store_init,
NULL
};
store_type = g_type_register_static (G_TYPE_OBJECT,
"GstBufferStore",
&store_info, 0);
/* FIXME: better description anyone? */
GST_DEBUG_CATEGORY_INIT (gst_buffer_store_debug, "bufferstore", 0, "store all data");
}
return store_type;
}
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_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstBufferStoreClass *store_class;
gobject_class = G_OBJECT_CLASS (g_class);
store_class = GST_BUFFER_STORE_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_class);
gobject_class->dispose = gst_buffer_store_dispose;
gst_buffer_store_signals[CLEARED] = g_signal_new ("cleared",
G_TYPE_FROM_CLASS (g_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 (g_class), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstBufferStoreClass, buffer_added), continue_accu, NULL,
gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
store_class->cleared = gst_buffer_store_cleared_func;
store_class->buffer_added = gst_buffer_store_add_buffer_func;
}
static void
gst_buffer_store_init (GTypeInstance *instance, gpointer g_class)
{
GstBufferStore *store = GST_BUFFER_STORE (instance);
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)
{
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 */
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_data_ref (GST_DATA (buffer));
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));
/* 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_OFFSET (current)) {
g_assert (needed_size == GST_BUFFER_OFFSET (current)); /* we have no overlapping data */
buffer = NULL;
} 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);
buffer = sub;
} else {
gst_data_ref (GST_DATA (buffer));
}
/* replace current buffer with new one */
gst_data_unref (GST_DATA (current_list->data));
current_list->data = buffer;
buffer = NULL;
break;
}
} else if (GST_BUFFER_OFFSET (current) > GST_BUFFER_OFFSET (buffer)) {
GList *previous = g_list_previous (current_list);
guint64 start_offset = previous ?
GST_BUFFER_OFFSET (previous->data) + GST_BUFFER_SIZE (previous->data) : 0;
if (start_offset == GST_BUFFER_OFFSET (current)) {
buffer = NULL;
break;
} else {
/* we have data to insert */
if (start_offset > GST_BUFFER_OFFSET (buffer) ||
GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer) > GST_BUFFER_OFFSET (current)) {
/* need a subbuffer */
start_offset = GST_BUFFER_OFFSET (buffer) > start_offset ? 0 :
start_offset - GST_BUFFER_OFFSET (buffer);
GstBuffer* sub = gst_buffer_create_sub (buffer, start_offset,
MIN (GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (current) - start_offset));
buffer = sub;
} else {
gst_data_ref (GST_DATA (buffer));
}
store->buffers = g_list_insert_before (store->buffers, walk, buffer);
buffer = NULL;
break;
}
}
}
if (buffer) {
gst_data_ref (GST_DATA (buffer));
if (current_list) {
g_list_append (current_list, buffer);
} else {
g_assert (store->buffers == NULL);
store->buffers = g_list_prepend (NULL, buffer);
}
}
return TRUE;
}
}
static void
gst_buffer_store_cleared_func (GstBufferStore *store)
{
g_list_foreach (store->buffers, (GFunc) gst_data_unref, NULL);
g_list_free (store->buffers);
store->buffers = NULL;
}
/**
* gst_buffer_store_new:
*
* Creates a new bufferstore.
*
* Returns: the new bufferstore.
*/
GstBufferStore *
gst_buffer_store_new (void)
{
return GST_BUFFER_STORE (g_object_new (GST_TYPE_BUFFER_STORE, NULL));
}
/**
* gst_buffer_store_clear:
* @store: a bufferstore
*
* Clears the buffer store. All buffers are removed and the buffer store
* behaves like it was just created.
*/
/* FIXME: call this function _reset ? */
void
gst_buffer_store_clear (GstBufferStore *store)
{
g_return_if_fail (GST_IS_BUFFER_STORE (store));
g_signal_emit (store, gst_buffer_store_signals [CLEARED], 0, NULL);
}
/**
* gst_buffer_store_add_buffer:
* @store: a bufferstore
* @buffer: the buffer to add
*
* Adds a buffer to the buffer store.
*
* Returns: TRUE, if the buffer was added, FALSE if an error occured.
*/
gboolean
gst_buffer_store_add_buffer (GstBufferStore *store, GstBuffer *buffer)
{
gboolean ret;
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
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;
guint64 cur_offset;
gboolean have_offset;
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;
cur_offset = 0;
}
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 &&
GST_BUFFER_SIZE (current) == size) {
GST_LOG_OBJECT (store, "found matching buffer %p for offset %"G_GUINT64_FORMAT" and size %u",
current, offset, size);
ret = current;
gst_data_ref (GST_DATA (ret));
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_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 &&
cur_offset + GST_BUFFER_SIZE (current) != GST_BUFFER_OFFSET (walk->data))) {
GST_DEBUG_OBJECT (store, "not all data for offset %"G_GUINT64_FORMAT" and size %u available, aborting",
offset, size);
gst_data_unref (GST_DATA (ret));
ret = NULL;
break;
}
current = GST_BUFFER (walk->data);
walk = g_list_next (walk);
tmp = MIN (GST_BUFFER_SIZE (current), size);
memcpy (data, GST_BUFFER_DATA (current), tmp);
size -= tmp;
}
}
if (!have_offset) {
cur_offset += GST_BUFFER_SIZE (current);
}
}
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;
guint64 cur_offset;
gboolean have_offset;
gboolean counting = FALSE;
GstBuffer *current;
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;
cur_offset = 0;
}
while (walk) {
if (have_offset &&
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;
}

View file

@ -0,0 +1,73 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.h: keep an easily accessible list of all buffers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_BUFFER_STORE_H__
#define __GST_BUFFER_STORE_H__
#include <gst/gstbuffer.h>
#include <gst/gstinfo.h>
#include <gst/gstmarshal.h>
G_BEGIN_DECLS
#define GST_TYPE_BUFFER_STORE (gst_buffer_store_get_type ())
#define GST_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_BUFFER_STORE, GstBufferStore))
#define GST_IS_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_BUFFER_STORE))
#define GST_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
#define GST_IS_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_BUFFER_STORE))
#define GST_BUFFER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
typedef struct _GstBufferStore GstBufferStore;
typedef struct _GstBufferStoreClass GstBufferStoreClass;
struct _GstBufferStore {
GObject object;
GList * buffers;
};
struct _GstBufferStoreClass {
GObjectClass parent_class;
/* signals */
void (* cleared) (GstBufferStore * store);
gboolean (* buffer_added) (GstBufferStore * store,
GstBuffer * buffer);
};
GType gst_buffer_store_get_type (void);
GstBufferStore * gst_buffer_store_new (void);
void gst_buffer_store_clear (GstBufferStore * store);
gboolean gst_buffer_store_add_buffer (GstBufferStore * store,
GstBuffer * buffer);
GstBuffer * gst_buffer_store_get_buffer (GstBufferStore * store,
guint64 offset,
guint size);
guint gst_buffer_store_get_size (GstBufferStore * store,
guint64 offset);
G_END_DECLS
#endif /* __GST_BUFFER_STORE_H__ */

View file

@ -27,20 +27,21 @@
#include <gst/gst.h>
#include "gstfilesrc.h"
#include "gstfilesink.h"
#include "gstidentity.h"
#include "gstaggregator.h"
#include "gstfakesink.h"
#include "gstfakesrc.h"
#include "gstfdsink.h"
#include "gstfdsrc.h"
#include "gstfilesink.h"
#include "gstfilesrc.h"
#include "gstidentity.h"
#include "gstmd5sink.h"
#include "gstmultidisksrc.h"
#include "gstpipefilter.h"
#include "gsttee.h"
#include "gstaggregator.h"
#include "gstshaper.h"
#include "gststatistics.h"
#include "gstmd5sink.h"
#include "gsttee.h"
#include "gsttypefindelement.h"
struct _elements_entry {
@ -55,20 +56,21 @@ extern GType gst_filesrc_get_type(void);
extern GstElementDetails gst_filesrc_details;
static struct _elements_entry _elements[] = {
{ "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, gst_fakesrc_factory_init },
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, gst_fakesink_factory_init },
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
{ "filesrc", gst_filesrc_get_type, &gst_filesrc_details, NULL },
{ "filesink", gst_filesink_get_type, &gst_filesink_details, NULL },
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
{ "multidisksrc", gst_multidisksrc_get_type, &gst_multidisksrc_details, NULL },
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
{ "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
{ "shaper", gst_shaper_get_type, &gst_shaper_details, gst_shaper_factory_init },
{ "statistics", gst_statistics_get_type, &gst_statistics_details, NULL },
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
{ "typefind", gst_type_find_element_get_type, &gst_type_find_element_details, NULL },
{ NULL, 0 },
};
@ -80,20 +82,21 @@ plugin_init (GModule *module, GstPlugin *plugin)
gst_plugin_set_longname (plugin, "Standard GST Elements");
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "fakesink", 0, "filesink element");
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0, "filesink element");
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
GST_DEBUG_CATEGORY_INIT (gst_multidisksrc_debug, "multidisksrc", 0, "multidisksrc element");
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", 0, "typefind element");
while (_elements[i].name) {
factory = gst_element_factory_new (_elements[i].name,
@ -112,12 +115,10 @@ plugin_init (GModule *module, GstPlugin *plugin)
_elements[i].factoryinit (factory);
}
/* g_print("added factory '%s'\n",_elements[i].name); */
i++;
}
/* INFO (GST_INFO_PLUGIN_LOAD,"gstelements: loaded %d standard elements", i);*/
return TRUE;
}

View file

@ -0,0 +1,563 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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.
*/
/* 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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gsttypefindelement.h"
#include "gst/gst_private.h"
#include <gst/gsttypefind.h>
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
#define GST_CAT_DEFAULT gst_type_find_element_debug
GstElementDetails gst_type_find_element_details = {
"TypeFind",
"Generic",
"LGPL",
"Finds the media type of a stream",
VERSION,
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
"(C) 2003",
};
/* generic templates */
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_CAPS_ANY
);
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_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 */
};
static void gst_type_find_element_class_init (gpointer g_class,
gpointer class_data);
static void gst_type_find_element_init (GTypeInstance *instance,
gpointer g_class);
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);
static void gst_type_find_element_chain (GstPad * sinkpad,
GstData * data);
static GstElementStateReturn
gst_type_find_element_change_state (GstElement * element);
static GstElementClass *parent_class = NULL;
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
GType
gst_type_find_element_get_type (void)
{
static GType typefind_type = 0;
if (!typefind_type) {
static const GTypeInfo typefind_info = {
sizeof (GstTypeFindElementClass),
NULL,
NULL,
gst_type_find_element_class_init,
NULL,
NULL,
sizeof (GstTypeFindElement),
0,
gst_type_find_element_init,
NULL
};
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstTypeFindElement",
&typefind_info, 0);
}
return typefind_type;
}
static void
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
{
gchar *caps_str;
g_assert (typefind->caps == NULL);
caps_str = gst_caps_to_string (caps);
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
g_free (caps_str);
gst_caps_replace (&typefind->caps, caps);
if (!gst_pad_try_set_caps (typefind->src, caps)) {
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
}
}
static void
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstTypeFindElementClass *typefind_class;
gobject_class = G_OBJECT_CLASS (g_class);
gstelement_class = GST_ELEMENT_CLASS (g_class);
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_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);
g_object_class_install_property (gobject_class, ARG_CAPS,
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
GST_TYPE_CAPS, 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 (g_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);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
typefind_class->have_type = gst_type_find_element_have_type;
}
static void
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
/* sinkpad */
typefind->sink = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
gst_pad_set_chain_function (typefind->sink,
gst_type_find_element_chain);
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
/* srcpad */
typefind->src = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
typefind->caps = NULL;
typefind->min_probability = 1;
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
typefind->store = gst_buffer_store_new ();
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_type_find_element_dispose (GObject *object)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
if (typefind->store) {
g_object_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 void
start_typefinding (GstTypeFindElement *typefind)
{
g_assert (typefind->caps == NULL);
typefind->mode = MODE_TYPEFIND;
}
static void
stop_typefinding (GstTypeFindElement *typefind, gboolean push_cached_buffers)
{
/* stop all typefinding and set mode back to normal */
g_assert (typefind->possibilities == NULL);
typefind->mode = MODE_NORMAL;
if (push_cached_buffers) {
guint size = gst_buffer_store_get_size (typefind->store, 0);
GstBuffer *buffer = gst_buffer_store_get_buffer (typefind->store, 0, size);
if (buffer) {
gst_pad_push (typefind->sink, GST_DATA (buffer));
} else {
size = 0;
}
gst_pad_send_event (GST_PAD_PEER (typefind->sink),
gst_event_new_seek (GST_SEEK_METHOD_SET, size));
}
gst_buffer_store_clear (typefind->store);
}
static void
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
{
gst_pad_event_default (pad, event);
}
typedef struct {
GstTypeFindFactory * factory;
gint probability;
GstCaps * caps;
gint64 requested_offset;
guint requested_size;
GList * buffers;
GstTypeFindElement * self;
} TypeFindEntry;
static void
free_entry_buffers (TypeFindEntry *entry)
{
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
g_list_free (entry->buffers);
entry->buffers = NULL;
}
static void
free_entry (TypeFindEntry *entry)
{
free_entry_buffers (entry);
if (entry->caps)
gst_caps_unref (entry->caps);
g_free (entry);
}
static guint64
find_element_get_length (gpointer data)
{
TypeFindEntry *entry = (TypeFindEntry *) data;
GstTypeFindElement *typefind = entry->self;
GstFormat format = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length ()",
GST_PLUGIN_FEATURE_NAME (entry->factory));
if (!typefind->stream_length_available)
return 0;
if (entry->self->stream_length == 0) {
typefind->stream_length_available = gst_pad_query (entry->self->sink, GST_QUERY_TOTAL,
&format, &entry->self->stream_length);
if (format != GST_FORMAT_BYTES)
typefind->stream_length_available = FALSE;
if (!typefind->stream_length_available)
return 0;
}
return entry->self->stream_length;
}
static guint8 *
find_peek (gpointer data, gint64 offset, guint size)
{
GstBuffer *buf;
TypeFindEntry *entry = (TypeFindEntry *) data;
GST_DEBUG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
if (offset >= 0) {
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
} else {
/* FIXME: can we do this easily without querying length? */
guint64 length = find_element_get_length (data);
if (length == 0) {
buf = NULL;
} else {
buf = gst_buffer_store_get_buffer (entry->self->store, length - offset, size);
}
}
if (buf) {
entry->buffers = g_list_prepend (entry->buffers, buf);
return GST_BUFFER_DATA (buf);
} else {
if (entry->requested_size == 0) {
entry->requested_offset = offset;
entry->requested_size = size;
}
return NULL;
}
}
static void
find_suggest (gpointer data, guint probability, GstCaps *caps)
{
gchar *str;
TypeFindEntry *entry = (TypeFindEntry *) data;
str = gst_caps_to_string (caps);
GST_DEBUG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
g_free (str);
if (((gint) probability) > entry->probability) {
entry->probability = probability;
gst_caps_replace (&entry->caps, caps);
}
}
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;
}
}
static void
gst_type_find_element_chain (GstPad *pad, GstData *data)
{
GstTypeFindElement *typefind;
GList *entries;
TypeFindEntry *entry;
GList *walk;
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
if (GST_IS_EVENT (data)) {
gst_type_find_element_handle_event (pad, GST_EVENT (data));
return;
}
switch (typefind->mode) {
case MODE_NORMAL:
gst_pad_push (typefind->src, data);
return;
case MODE_TYPEFIND: {
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
gst_data_unref (data);
if (typefind->possibilities == NULL) {
/* not yet started, get all typefinding functions into our "queue" */
const GList *all_factories = gst_type_find_factory_get_list ();
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
g_list_length ((GList *) all_factories));
while (all_factories) {
entry = g_new0 (TypeFindEntry, 1);
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
entry->self = typefind;
entry->probability = -1;
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
all_factories = g_list_next (all_factories);
}
}
/* call every typefind function once */
walk = entries = typefind->possibilities;
GST_DEBUG_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);
entry->probability = -1;
entry->requested_offset = 0;
entry->requested_size = 0;
gst_type_find_factory_call_function (entry->factory, &find);
free_entry_buffers (entry);
if (entry->probability == -1) {
free_entry (entry);
} else if (entry->probability >= typefind->max_probability) {
/* wooha, got caps */
GstCaps *found_caps = entry->caps;
guint probability = entry->probability;
gst_caps_ref (found_caps);
GST_LOG_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);
}
typefind->possibilities = NULL;
g_list_free (typefind->possibilities);
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], probability, found_caps);
gst_caps_unref (found_caps);
} else {
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
}
}
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, TRUE);
} else if (typefind->possibilities == NULL) {
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
} else {
/* set up typefind element for next iteration */
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
walk = typefind->possibilities;
while (walk) {
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size > 0) {
/* FIXME: need heuristic to find out if we should seek */
GstEvent *event = gst_event_new_seek (entry->requested_offset < 0 ?
GST_SEEK_METHOD_SET : GST_SEEK_METHOD_END, entry->requested_offset);
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
/* done seeking */
break;
} else {
/* impossible to seek */
entry->requested_size = 0;
entry->requested_offset = 0;
}
}
}
/* throw out all entries that can't get more data */
walk = g_list_next (typefind->possibilities);
while (walk) {
GList *cur = walk;
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size == 0) {
free_entry (entry);
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
}
}
if (g_list_next (typefind->possibilities) == NULL) {
entry = (TypeFindEntry *) typefind->possibilities->data;
GST_LOG_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], entry->probability, entry->caps);
free_entry (entry);
g_list_free (typefind->possibilities);
typefind->possibilities = NULL;
stop_typefinding (typefind, TRUE);
}
}
break;
}
default:
g_assert_not_reached ();
return;
}
}
static GstElementStateReturn
gst_type_find_element_change_state (GstElement *element)
{
GstTypeFindElement *typefind;
typefind = GST_TYPE_FIND_ELEMENT (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_PAUSED:
start_typefinding (typefind);
break;
case GST_STATE_PAUSED_TO_READY:
stop_typefinding (typefind, FALSE);
gst_caps_replace (&typefind->caps, NULL);
break;
default:
break;
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
}

View file

@ -0,0 +1,78 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
extern GstElementDetails gst_type_find_element_details;
#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;
GstBufferStore * store;
guint64 stream_length;
gboolean stream_length_available;
GList * possibilities;
};
struct _GstTypeFindElementClass {
GstElementClass parent_class;
/* signals */
void (*have_type) (GstTypeFindElement *element,
guint probability,
GstCaps * caps);
};
GType gst_type_find_element_get_type (void);
G_END_DECLS
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */

View file

@ -0,0 +1,563 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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.
*/
/* 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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gsttypefindelement.h"
#include "gst/gst_private.h"
#include <gst/gsttypefind.h>
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
#define GST_CAT_DEFAULT gst_type_find_element_debug
GstElementDetails gst_type_find_element_details = {
"TypeFind",
"Generic",
"LGPL",
"Finds the media type of a stream",
VERSION,
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
"(C) 2003",
};
/* generic templates */
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_CAPS_ANY
);
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_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 */
};
static void gst_type_find_element_class_init (gpointer g_class,
gpointer class_data);
static void gst_type_find_element_init (GTypeInstance *instance,
gpointer g_class);
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);
static void gst_type_find_element_chain (GstPad * sinkpad,
GstData * data);
static GstElementStateReturn
gst_type_find_element_change_state (GstElement * element);
static GstElementClass *parent_class = NULL;
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
GType
gst_type_find_element_get_type (void)
{
static GType typefind_type = 0;
if (!typefind_type) {
static const GTypeInfo typefind_info = {
sizeof (GstTypeFindElementClass),
NULL,
NULL,
gst_type_find_element_class_init,
NULL,
NULL,
sizeof (GstTypeFindElement),
0,
gst_type_find_element_init,
NULL
};
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstTypeFindElement",
&typefind_info, 0);
}
return typefind_type;
}
static void
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
{
gchar *caps_str;
g_assert (typefind->caps == NULL);
caps_str = gst_caps_to_string (caps);
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
g_free (caps_str);
gst_caps_replace (&typefind->caps, caps);
if (!gst_pad_try_set_caps (typefind->src, caps)) {
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
}
}
static void
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstTypeFindElementClass *typefind_class;
gobject_class = G_OBJECT_CLASS (g_class);
gstelement_class = GST_ELEMENT_CLASS (g_class);
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_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);
g_object_class_install_property (gobject_class, ARG_CAPS,
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
GST_TYPE_CAPS, 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 (g_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);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
typefind_class->have_type = gst_type_find_element_have_type;
}
static void
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
/* sinkpad */
typefind->sink = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
gst_pad_set_chain_function (typefind->sink,
gst_type_find_element_chain);
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
/* srcpad */
typefind->src = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
typefind->caps = NULL;
typefind->min_probability = 1;
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
typefind->store = gst_buffer_store_new ();
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_type_find_element_dispose (GObject *object)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
if (typefind->store) {
g_object_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 void
start_typefinding (GstTypeFindElement *typefind)
{
g_assert (typefind->caps == NULL);
typefind->mode = MODE_TYPEFIND;
}
static void
stop_typefinding (GstTypeFindElement *typefind, gboolean push_cached_buffers)
{
/* stop all typefinding and set mode back to normal */
g_assert (typefind->possibilities == NULL);
typefind->mode = MODE_NORMAL;
if (push_cached_buffers) {
guint size = gst_buffer_store_get_size (typefind->store, 0);
GstBuffer *buffer = gst_buffer_store_get_buffer (typefind->store, 0, size);
if (buffer) {
gst_pad_push (typefind->sink, GST_DATA (buffer));
} else {
size = 0;
}
gst_pad_send_event (GST_PAD_PEER (typefind->sink),
gst_event_new_seek (GST_SEEK_METHOD_SET, size));
}
gst_buffer_store_clear (typefind->store);
}
static void
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
{
gst_pad_event_default (pad, event);
}
typedef struct {
GstTypeFindFactory * factory;
gint probability;
GstCaps * caps;
gint64 requested_offset;
guint requested_size;
GList * buffers;
GstTypeFindElement * self;
} TypeFindEntry;
static void
free_entry_buffers (TypeFindEntry *entry)
{
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
g_list_free (entry->buffers);
entry->buffers = NULL;
}
static void
free_entry (TypeFindEntry *entry)
{
free_entry_buffers (entry);
if (entry->caps)
gst_caps_unref (entry->caps);
g_free (entry);
}
static guint64
find_element_get_length (gpointer data)
{
TypeFindEntry *entry = (TypeFindEntry *) data;
GstTypeFindElement *typefind = entry->self;
GstFormat format = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length ()",
GST_PLUGIN_FEATURE_NAME (entry->factory));
if (!typefind->stream_length_available)
return 0;
if (entry->self->stream_length == 0) {
typefind->stream_length_available = gst_pad_query (entry->self->sink, GST_QUERY_TOTAL,
&format, &entry->self->stream_length);
if (format != GST_FORMAT_BYTES)
typefind->stream_length_available = FALSE;
if (!typefind->stream_length_available)
return 0;
}
return entry->self->stream_length;
}
static guint8 *
find_peek (gpointer data, gint64 offset, guint size)
{
GstBuffer *buf;
TypeFindEntry *entry = (TypeFindEntry *) data;
GST_DEBUG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
if (offset >= 0) {
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
} else {
/* FIXME: can we do this easily without querying length? */
guint64 length = find_element_get_length (data);
if (length == 0) {
buf = NULL;
} else {
buf = gst_buffer_store_get_buffer (entry->self->store, length - offset, size);
}
}
if (buf) {
entry->buffers = g_list_prepend (entry->buffers, buf);
return GST_BUFFER_DATA (buf);
} else {
if (entry->requested_size == 0) {
entry->requested_offset = offset;
entry->requested_size = size;
}
return NULL;
}
}
static void
find_suggest (gpointer data, guint probability, GstCaps *caps)
{
gchar *str;
TypeFindEntry *entry = (TypeFindEntry *) data;
str = gst_caps_to_string (caps);
GST_DEBUG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
g_free (str);
if (((gint) probability) > entry->probability) {
entry->probability = probability;
gst_caps_replace (&entry->caps, caps);
}
}
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;
}
}
static void
gst_type_find_element_chain (GstPad *pad, GstData *data)
{
GstTypeFindElement *typefind;
GList *entries;
TypeFindEntry *entry;
GList *walk;
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
if (GST_IS_EVENT (data)) {
gst_type_find_element_handle_event (pad, GST_EVENT (data));
return;
}
switch (typefind->mode) {
case MODE_NORMAL:
gst_pad_push (typefind->src, data);
return;
case MODE_TYPEFIND: {
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
gst_data_unref (data);
if (typefind->possibilities == NULL) {
/* not yet started, get all typefinding functions into our "queue" */
const GList *all_factories = gst_type_find_factory_get_list ();
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
g_list_length ((GList *) all_factories));
while (all_factories) {
entry = g_new0 (TypeFindEntry, 1);
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
entry->self = typefind;
entry->probability = -1;
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
all_factories = g_list_next (all_factories);
}
}
/* call every typefind function once */
walk = entries = typefind->possibilities;
GST_DEBUG_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);
entry->probability = -1;
entry->requested_offset = 0;
entry->requested_size = 0;
gst_type_find_factory_call_function (entry->factory, &find);
free_entry_buffers (entry);
if (entry->probability == -1) {
free_entry (entry);
} else if (entry->probability >= typefind->max_probability) {
/* wooha, got caps */
GstCaps *found_caps = entry->caps;
guint probability = entry->probability;
gst_caps_ref (found_caps);
GST_LOG_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);
}
typefind->possibilities = NULL;
g_list_free (typefind->possibilities);
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], probability, found_caps);
gst_caps_unref (found_caps);
} else {
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
}
}
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, TRUE);
} else if (typefind->possibilities == NULL) {
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
} else {
/* set up typefind element for next iteration */
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
walk = typefind->possibilities;
while (walk) {
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size > 0) {
/* FIXME: need heuristic to find out if we should seek */
GstEvent *event = gst_event_new_seek (entry->requested_offset < 0 ?
GST_SEEK_METHOD_SET : GST_SEEK_METHOD_END, entry->requested_offset);
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
/* done seeking */
break;
} else {
/* impossible to seek */
entry->requested_size = 0;
entry->requested_offset = 0;
}
}
}
/* throw out all entries that can't get more data */
walk = g_list_next (typefind->possibilities);
while (walk) {
GList *cur = walk;
entry = (TypeFindEntry *) walk->data;
walk = g_list_next (walk);
if (entry->requested_size == 0) {
free_entry (entry);
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
}
}
if (g_list_next (typefind->possibilities) == NULL) {
entry = (TypeFindEntry *) typefind->possibilities->data;
GST_LOG_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], entry->probability, entry->caps);
free_entry (entry);
g_list_free (typefind->possibilities);
typefind->possibilities = NULL;
stop_typefinding (typefind, TRUE);
}
}
break;
}
default:
g_assert_not_reached ();
return;
}
}
static GstElementStateReturn
gst_type_find_element_change_state (GstElement *element)
{
GstTypeFindElement *typefind;
typefind = GST_TYPE_FIND_ELEMENT (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_READY_TO_PAUSED:
start_typefinding (typefind);
break;
case GST_STATE_PAUSED_TO_READY:
stop_typefinding (typefind, FALSE);
gst_caps_replace (&typefind->caps, NULL);
break;
default:
break;
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
}

View file

@ -0,0 +1,78 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gsttypefind.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
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
extern GstElementDetails gst_type_find_element_details;
#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;
GstBufferStore * store;
guint64 stream_length;
gboolean stream_length_available;
GList * possibilities;
};
struct _GstTypeFindElementClass {
GstElementClass parent_class;
/* signals */
void (*have_type) (GstTypeFindElement *element,
guint probability,
GstCaps * caps);
};
GType gst_type_find_element_get_type (void);
G_END_DECLS
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */

View file

@ -112,18 +112,11 @@ print_props (GstProps *properties, const gchar *pfx)
}
static void
print_caps (const GstCaps *caps, const gchar *pfx)
print_caps (GstCaps *caps, const gchar *pfx)
{
while (caps) {
GstType *type;
g_print ("%s'%s': (%sfixed)\n", pfx, caps->name, (GST_CAPS_IS_FIXED (caps) ? "" : "NOT "));
type = gst_type_find_by_id (caps->id);
if (type)
g_print ("%s MIME type: '%s':\n", pfx, type->mime);
else
g_print ("%s MIME type: 'unknown/unknown':\n", pfx);
g_print ("%s MIME type: '%s':\n", pfx, gst_caps_get_mime (caps));
if (caps->properties) {
gchar *prefix = g_strdup_printf ("%s ", pfx);
@ -863,20 +856,19 @@ print_element_list (void)
GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
}
#endif
else if (GST_IS_TYPE_FACTORY (feature)) {
GstTypeFactory *factory;
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
GstTypeFindFactory *factory;
factory = GST_TYPE_FACTORY (feature);
if (factory->exts)
g_print ("%s type: %s: %s\n", plugin->name,
factory->mime, factory->exts);
else
g_print ("%s type: %s: N/A\n", plugin->name,
factory->mime);
if (factory->typefindfunc)
g_print (" Has typefind function: %s\n",
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
factory = GST_TYPE_FIND_FACTORY (feature);
if (factory->extensions) {
guint i;
g_print ("%s type: ", plugin->name);
while (factory->extensions[i]) {
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
i++;
}
} else
g_print ("%s type: N/A\n", plugin->name);
}
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
GstSchedulerFactory *factory;
@ -957,15 +949,20 @@ print_plugin_info (GstPlugin *plugin)
num_indexes++;
}
#endif
else if (GST_IS_TYPE_FACTORY (feature)) {
GstTypeFactory *factory;
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
GstTypeFindFactory *factory;
factory = GST_TYPE_FACTORY (feature);
g_print (" %s: %s\n", factory->mime, factory->exts);
factory = GST_TYPE_FIND_FACTORY (feature);
if (factory->extensions) {
guint i;
g_print ("%s type: ", plugin->name);
while (factory->extensions[i]) {
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
i++;
}
} else
g_print ("%s type: N/A\n", plugin->name);
if (factory->typefindfunc)
g_print (" Has typefind function: %s\n",
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
num_types++;
}
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
@ -1066,9 +1063,9 @@ main (int argc, char *argv[])
}
#endif
feature = gst_registry_pool_find_feature (argv[1],
GST_TYPE_TYPE_FACTORY);
GST_TYPE_TYPE_FIND_FACTORY);
if (feature) {
g_print ("%s: an type\n", argv[1]);
g_print ("%s: a typefind function\n", argv[1]);
return 0;
}
#ifndef GST_DISABLE_URI

View file

@ -132,7 +132,7 @@ int main (int argc,char *argv[])
dir_list = gst_registry_get_path_list(registry);
for(iter = dir_list; iter; iter = iter->next) {
dir = g_build_filename((const char *)iter->data, "register-scripts");
dir = g_build_filename((const char *)iter->data, "register-scripts", NULL);
spawn_all_in_dir(dir);
g_free(dir);
}

View file

@ -159,7 +159,7 @@ print_props (GstProps *properties, gint pfx)
}
static void
print_caps (const GstCaps *caps, gint pfx)
print_caps (GstCaps *caps, gint pfx)
{
if (!caps)
return;
@ -167,16 +167,10 @@ print_caps (const GstCaps *caps, gint pfx)
PUT_START_TAG (pfx, "capscomp");
while (caps) {
GstType *type;
PUT_START_TAG (pfx + 1, "caps");
PUT_ESCAPED (pfx + 2, "name", caps->name);
type = gst_type_find_by_id (caps->id);
if (type)
PUT_ESCAPED (pfx + 2, "type", type->mime);
else
PUT_ESCAPED (pfx + 2, "type", "unkown/unknown");
PUT_ESCAPED (pfx + 2, "type", gst_caps_get_mime (caps));
if (caps->properties) {
print_props(caps->properties, pfx + 2);
@ -855,16 +849,19 @@ print_element_list (void)
GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
}
#endif
else if (GST_IS_TYPE_FACTORY (feature)) {
GstTypeFactory *factory;
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
GstTypeFindFactory *factory;
factory = GST_TYPE_FACTORY (feature);
g_print ("%s type: %s: %s\n", plugin->name,
factory->mime, factory->exts);
if (factory->typefindfunc)
g_print (" Has typefind function: %s\n",
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
factory = GST_TYPE_FIND_FACTORY (feature);
if (factory->extensions) {
guint i;
g_print ("%s type: ", plugin->name);
while (factory->extensions[i]) {
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
i++;
}
} else
g_print ("%s type: N/A\n", plugin->name);
}
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
GstSchedulerFactory *factory;
@ -945,15 +942,19 @@ print_plugin_info (GstPlugin *plugin)
num_indexes++;
}
#endif
else if (GST_IS_TYPE_FACTORY (feature)) {
GstTypeFactory *factory;
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
GstTypeFindFactory *factory;
factory = GST_TYPE_FACTORY (feature);
g_print (" %s: %s\n", factory->mime, factory->exts);
if (factory->typefindfunc)
g_print (" Has typefind function: %s\n",
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
factory = GST_TYPE_FIND_FACTORY (feature);
if (factory->extensions) {
guint i;
g_print ("%s type: ", plugin->name);
while (factory->extensions[i]) {
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
i++;
}
} else
g_print ("%s type: N/A\n", plugin->name);
num_types++;
}
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
@ -1059,9 +1060,9 @@ main (int argc, char *argv[])
}
#endif
feature = gst_registry_pool_find_feature (argv[1],
GST_TYPE_TYPE_FACTORY);
GST_TYPE_TYPE_FIND_FACTORY);
if (feature) {
g_print ("%s: an type\n", argv[1]);
g_print ("%s: a type find function\n", argv[1]);
return 0;
}
#ifndef GST_DISABLE_URI