[svn r76] typefind copyed from gstreamer cvs trunk
authorrenatofilho
Thu Nov 09 19:45:27 2006 +0000 (2006-11-09)
branchtrunk
changeset 75761a8bbe4278
parent 74 ce823be21819
child 76 1c1958d4bab7
[svn r76] typefind copyed from gstreamer cvs
gst-plugins-nuvdemux/Makefile.am
gst-plugins-nuvdemux/configure.ac
gst-plugins-nuvdemux/debian/rules
gst-plugins-nuvdemux/nuvdemux/Makefile.am
gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c
gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.h
gst-plugins-nuvdemux/src/Makefile.am
gst-plugins-nuvdemux/src/gstnuvdemux.c
gst-plugins-nuvdemux/src/gstnuvdemux.h
gst-plugins-nuvdemux/typefind/Makefile.am
gst-plugins-nuvdemux/typefind/gsttypefindfunctions.c
     1.1 --- a/gst-plugins-nuvdemux/Makefile.am	Thu Nov 09 19:12:55 2006 +0000
     1.2 +++ b/gst-plugins-nuvdemux/Makefile.am	Thu Nov 09 19:45:27 2006 +0000
     1.3 @@ -1,4 +1,4 @@
     1.4  ACLOCAL_AMFLAGS = -I m4
     1.5  
     1.6 -SUBDIRS = src
     1.7 +SUBDIRS = nuvdemux typefind
     1.8  DIST_SUBDIRS = m4
     2.1 --- a/gst-plugins-nuvdemux/configure.ac	Thu Nov 09 19:12:55 2006 +0000
     2.2 +++ b/gst-plugins-nuvdemux/configure.ac	Thu Nov 09 19:45:27 2006 +0000
     2.3 @@ -123,7 +123,8 @@
     2.4  
     2.5  AC_OUTPUT( \
     2.6      Makefile \
     2.7 -    src/Makefile \
     2.8 +    nuvdemux/Makefile \
     2.9 +    typefind/Makefile \
    2.10      m4/Makefile
    2.11  )
    2.12  
     3.1 --- a/gst-plugins-nuvdemux/debian/rules	Thu Nov 09 19:12:55 2006 +0000
     3.2 +++ b/gst-plugins-nuvdemux/debian/rules	Thu Nov 09 19:45:27 2006 +0000
     3.3 @@ -8,4 +8,5 @@
     3.4  binary-install/gstreamer0.10-indt-nuvdemux::
     3.5  	rm -f debian/gstreamer0.10-indt-nuvdemux/usr/lib/gstreamer-0.10/libgstnuvdemux.la
     3.6  	rm -f debian/gstreamer0.10-indt-nuvdemux/usr/lib/gstreamer-0.10/libgstnuvdemux.a
     3.7 -
     3.8 +	rm -f debian/gstreamer0.10-indt-nuvdemux/usr/lib/gstreamer-0.10/libgsttypefindfunctions.la
     3.9 +	rm -f debian/gstreamer0.10-indt-nuvdemux/usr/lib/gstreamer-0.10/libgsttypefindfunctions.a
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/gst-plugins-nuvdemux/nuvdemux/Makefile.am	Thu Nov 09 19:45:27 2006 +0000
     4.3 @@ -0,0 +1,20 @@
     4.4 +plugin_LTLIBRARIES = libgstnuvdemux.la
     4.5 +
     4.6 +libgstnuvdemux_la_SOURCES =	\
     4.7 +	gstnuvdemux.c 
     4.8 +
     4.9 +libgstnuvdemux_la_CFLAGS = \
    4.10 +	$(GST_CFLAGS) \
    4.11 +	$(GST_PLUGINS_BASE_CFLAGS)
    4.12 +
    4.13 +libgstnuvdemux_la_LIBADD = \
    4.14 +	$(GST_LIBS_LIBS)
    4.15 +
    4.16 +libgstnuvdemux_la_LDFLAGS = \
    4.17 +	$(GST_PLUGIN_LDFLAGS) \
    4.18 +	$(GST_BASE_LIBS) \
    4.19 +	$(GST_PLUGINS_BASE_LIBS)
    4.20 +
    4.21 +noinst_HEADERS = \
    4.22 +	gstnuvdemux.h 
    4.23 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c	Thu Nov 09 19:45:27 2006 +0000
     5.3 @@ -0,0 +1,1137 @@
     5.4 +/* GStreamer
     5.5 + * Copyright (C) <2006> Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
     5.6 + *                      Rosfran Borges <rosfran.borges@indt.org.br>
     5.7 + *
     5.8 + * This library is free software; you can redistribute it and/or
     5.9 + * modify it under the terms of the GNU Library General Public
    5.10 + * License as published by the Free Software Foundation; either
    5.11 + * version 2 of the License, or (at your option) any later version.
    5.12 + *
    5.13 + * This library is distributed in the hope that it will be useful,
    5.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    5.16 + * Library General Public License for more details.
    5.17 + *
    5.18 + * You should have received a copy of the GNU Library General Public
    5.19 + * License along with this library; if not, write to the
    5.20 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    5.21 + * Boston, MA 02111-1307, USA.
    5.22 + */
    5.23 +/* Element-Checklist-Version: 5 */
    5.24 +
    5.25 +/**
    5.26 + * SECTION:element-nuvdemux
    5.27 + *
    5.28 + * <refsect2>
    5.29 + * <para>
    5.30 + * Demuxes an .nuv file into raw or compressed audio and/or video streams.
    5.31 + * </para>
    5.32 + * <para>
    5.33 + * This element currently only supports pull-based scheduling.
    5.34 + * </para>
    5.35 + * <title>Example launch line</title>
    5.36 + * <para>
    5.37 + * <programlisting>
    5.38 + * gst-launch filesrc test.nuv ! nuvdemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
    5.39 + * </programlisting>
    5.40 + * Play (parse and decode) an .nuv file and try to output it to
    5.41 + * an automatically detected soundcard and videosink. If the NUV file contains
    5.42 + * compressed audio or video data, this will only work if you have the
    5.43 + * right decoder elements/plugins installed.
    5.44 + * </para>
    5.45 + * </refsect2>
    5.46 + *
    5.47 + */
    5.48 +
    5.49 +#ifdef HAVE_CONFIG_H
    5.50 +#include "config.h"
    5.51 +#endif
    5.52 +
    5.53 +#include <gst/gst.h>
    5.54 +#include <gst/gsterror.h>
    5.55 +#include <gst/gstplugin.h>
    5.56 +#include <string.h>
    5.57 +
    5.58 +#include "glib/gi18n.h"
    5.59 +#include "gstnuvdemux.h"
    5.60 +
    5.61 +GST_DEBUG_CATEGORY_STATIC (nuvdemux_debug);
    5.62 +#define GST_CAT_DEFAULT nuvdemux_debug
    5.63 +
    5.64 +
    5.65 +#define GST_FLOW_ERROR_NO_DATA  -101
    5.66 +
    5.67 +GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT);
    5.68 +
    5.69 +static const GstElementDetails gst_nuv_demux_details =
    5.70 +GST_ELEMENT_DETAILS ("Nuv demuxer",
    5.71 +    "Codec/Demuxer",
    5.72 +    "Demultiplex a .nuv file into audio and video",
    5.73 +    "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
    5.74 +    "Rosfran Borges <rosfran.borges@indt.org.br>");
    5.75 +
    5.76 +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
    5.77 +    GST_PAD_SINK,
    5.78 +    GST_PAD_ALWAYS,
    5.79 +    GST_STATIC_CAPS ("video/x-nuv"));
    5.80 +
    5.81 +static GstStaticPadTemplate audio_src_template =
    5.82 +GST_STATIC_PAD_TEMPLATE ("audio_src",
    5.83 +    GST_PAD_SRC,
    5.84 +    GST_PAD_SOMETIMES,
    5.85 +    GST_STATIC_CAPS_ANY);
    5.86 +
    5.87 +static GstStaticPadTemplate video_src_template =
    5.88 +GST_STATIC_PAD_TEMPLATE ("video_src",
    5.89 +    GST_PAD_SRC,
    5.90 +    GST_PAD_SOMETIMES,
    5.91 +    GST_STATIC_CAPS_ANY);
    5.92 +
    5.93 +/* NUV Demux indexes init/dispose callers */
    5.94 +static void gst_nuv_demux_index_init( nuv_demux_index **p_idx );
    5.95 +static void gst_nuv_demux_index_clean( nuv_demux_index **p_idx );
    5.96 +
    5.97 +/* NUV Demux indexes manipulation functions */
    5.98 +//static gint64 gst_nuv_demux_index_find_offset( GstNuvDemux *nuv, gint64 i_offset );
    5.99 +static void gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset );
   5.100 +static gint64 gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time );
   5.101 +
   5.102 +/* NUV Demux plug-in time-line functions */
   5.103 +static void gst_nuv_demux_finalize (GObject * object);
   5.104 +static GstStateChangeReturn gst_nuv_demux_change_state (GstElement * element,
   5.105 +    GstStateChange transition);
   5.106 +static void gst_nuv_demux_loop (GstPad * pad);
   5.107 +static GstFlowReturn gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf);
   5.108 +static GstFlowReturn gst_nuv_demux_play (GstPad * pad);
   5.109 +static gboolean gst_nuv_demux_sink_activate_pull (GstPad * sinkpad,
   5.110 +    gboolean active);
   5.111 +static gboolean gst_nuv_demux_sink_activate (GstPad * sinkpad);
   5.112 +static GstFlowReturn gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size,
   5.113 +    gboolean move, GstBuffer ** buffer);
   5.114 +static void gst_nuv_demux_reset (GstNuvDemux * nuv);
   5.115 +static gboolean gst_nuv_demux_handle_sink_event (GstPad * sinkpad,
   5.116 +    GstEvent * event);
   5.117 +static gboolean gst_nuv_demux_handle_audio_src_event (GstPad * sinkpad,
   5.118 +    GstEvent * event);
   5.119 +static gboolean gst_nuv_demux_handle_video_src_event (GstPad * sinkpad,
   5.120 +    GstEvent * event);
   5.121 +static void gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv);
   5.122 +static void gst_nuv_demux_send_eos (GstNuvDemux * nuv);
   5.123 +
   5.124 +/* GObject methods */
   5.125 +GST_BOILERPLATE (GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
   5.126 +
   5.127 +#if G_BYTE_ORDER == G_BIG_ENDIAN
   5.128 +static inline gdouble
   5.129 +_gdouble_swap_le_be (gdouble * d)
   5.130 +{
   5.131 +  union
   5.132 +  {
   5.133 +    guint64 i;
   5.134 +    gdouble d;
   5.135 +  } u;
   5.136 +
   5.137 +  u.d = *d;
   5.138 +  u.i = GUINT64_SWAP_LE_BE (u.i);
   5.139 +  return u.d;
   5.140 +}
   5.141 +
   5.142 +#define READ_DOUBLE_FROM_LE(d) (_gdouble_swap_le_be((gdouble* ) d))
   5.143 +#else /* G_BYTE_ORDER != G_BIG_ENDIAN */
   5.144 +#define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
   5.145 +#endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
   5.146 +
   5.147 +static void
   5.148 +gst_nuv_demux_base_init (gpointer klass)
   5.149 +{
   5.150 +  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   5.151 +
   5.152 +  gst_element_class_add_pad_template (element_class,
   5.153 +      gst_static_pad_template_get (&audio_src_template));
   5.154 +
   5.155 +  gst_element_class_add_pad_template (element_class,
   5.156 +      gst_static_pad_template_get (&video_src_template));
   5.157 +
   5.158 +  gst_element_class_add_pad_template (element_class,
   5.159 +      gst_static_pad_template_get (&sink_template));
   5.160 +  gst_element_class_set_details (element_class, &gst_nuv_demux_details);
   5.161 +}
   5.162 +
   5.163 +static void
   5.164 +gst_nuv_demux_class_init (GstNuvDemuxClass * klass)
   5.165 +{
   5.166 +  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
   5.167 +  GObjectClass *gobject_class = (GObjectClass *) klass;
   5.168 +
   5.169 +  GST_DEBUG_CATEGORY_INIT (nuvdemux_debug, "nuvdemux",
   5.170 +      0, "Demuxer for NUV streams");
   5.171 +
   5.172 +  parent_class = g_type_class_peek_parent (klass);
   5.173 +
   5.174 +  gobject_class->finalize = gst_nuv_demux_finalize;
   5.175 +  gstelement_class->change_state = gst_nuv_demux_change_state;
   5.176 +}
   5.177 +
   5.178 +static void
   5.179 +gst_nuv_demux_init (GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
   5.180 +{
   5.181 +  nuv->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
   5.182 +
   5.183 +  gst_pad_set_activate_function (nuv->sinkpad, gst_nuv_demux_sink_activate);
   5.184 +
   5.185 +  gst_pad_set_activatepull_function (nuv->sinkpad,
   5.186 +      gst_nuv_demux_sink_activate_pull);
   5.187 +
   5.188 +  gst_pad_set_chain_function (nuv->sinkpad,
   5.189 +      GST_DEBUG_FUNCPTR (gst_nuv_demux_chain));
   5.190 +
   5.191 +  gst_pad_set_event_function (nuv->sinkpad, gst_nuv_demux_handle_sink_event);
   5.192 +
   5.193 +  gst_element_add_pad (GST_ELEMENT (nuv), nuv->sinkpad);
   5.194 +  
   5.195 +  gst_nuv_demux_index_init( &nuv->index_entries );
   5.196 +
   5.197 +  nuv->adapter = NULL;
   5.198 +  nuv->mpeg_buffer = NULL;
   5.199 +  nuv->h = NULL;
   5.200 +  nuv->eh = NULL;
   5.201 +  nuv->fh = NULL;
   5.202 +  gst_nuv_demux_reset (nuv);
   5.203 +}
   5.204 +
   5.205 +static void
   5.206 +gst_nuv_demux_finalize (GObject * object)
   5.207 +{
   5.208 +  GstNuvDemux *nuv = GST_NUV_DEMUX (object);
   5.209 +
   5.210 +  if (nuv->mpeg_buffer != NULL) {
   5.211 +    gst_buffer_unref (nuv->mpeg_buffer);
   5.212 +  }
   5.213 +  
   5.214 +  if ( nuv->index_entries != NULL ) {
   5.215 +  	gst_nuv_demux_index_clean( &nuv->index_entries );
   5.216 +  	nuv->index_entries = NULL;
   5.217 +  }
   5.218 +
   5.219 +  gst_nuv_demux_destoy_src_pad (nuv);
   5.220 +  gst_nuv_demux_reset (nuv);
   5.221 +  if (nuv->adapter != NULL) {
   5.222 +    gst_object_unref (nuv->adapter);
   5.223 +  }
   5.224 +  G_OBJECT_CLASS (parent_class)->finalize (object);
   5.225 +}
   5.226 +
   5.227 +
   5.228 +/*****************************************************************************
   5.229 + * Indexes (timecode offset conversion) functions
   5.230 + *****************************************************************************/
   5.231 +
   5.232 +static void 
   5.233 +gst_nuv_demux_index_init( nuv_demux_index **p_idx )
   5.234 +{
   5.235 +	*p_idx = g_new0( nuv_demux_index, 1 );
   5.236 +	(*p_idx)->i_idx = 0;
   5.237 +	(*p_idx)->i_idx_max = 0;
   5.238 +}
   5.239 +
   5.240 +static void 
   5.241 +gst_nuv_demux_index_clean( nuv_demux_index **p_idx )
   5.242 +{
   5.243 +	if ( *p_idx != NULL ) {
   5.244 +		g_free( *p_idx );
   5.245 +		*p_idx = NULL;
   5.246 +	}
   5.247 +
   5.248 +}
   5.249 +
   5.250 +static void 
   5.251 +gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset )
   5.252 +{
   5.253 +	nuv_demux_index *p_idx = nuv->index_entries;
   5.254 +
   5.255 +	//if ( p_idx == NULL )
   5.256 +	//	return;
   5.257 +
   5.258 +	/* Be sure to append new entry (we don't insert point) */
   5.259 +	if( p_idx != NULL && p_idx->i_idx > 0 && p_idx->idx[p_idx->i_idx-1].i_time >= i_time )
   5.260 +		return;
   5.261 +
   5.262 +	/* */
   5.263 +	if( p_idx->i_idx >= p_idx->i_idx_max )
   5.264 +	{
   5.265 +		if( p_idx->i_idx >= DEMUX_INDEX_SIZE_MAX )
   5.266 +		{
   5.267 +			/* Avoid too big index */
   5.268 +			const gint64 i_length = p_idx->idx[p_idx->i_idx-1].i_time -
   5.269 +				p_idx->idx[0].i_time;
   5.270 +			const gint i_count = DEMUX_INDEX_SIZE_MAX/2;
   5.271 +			gint i, j;
   5.272 +
   5.273 +			/* We try to reduce the resolution of the index by a factor 2 */
   5.274 +			for( i = 1, j = 1; i < p_idx->i_idx; i++ )
   5.275 +			{
   5.276 +				if( p_idx->idx[i].i_time < j * i_length / i_count )
   5.277 +					continue;
   5.278 +
   5.279 +				p_idx->idx[j++] = p_idx->idx[i];
   5.280 +			}
   5.281 +			p_idx->i_idx = j;
   5.282 +
   5.283 +			if( p_idx->i_idx > 3 * DEMUX_INDEX_SIZE_MAX / 4 )
   5.284 +			{
   5.285 +				/* We haven't created enough space
   5.286 +				 * (This method won't create a good index but work for sure) */
   5.287 +				for( i = 0; i < p_idx->i_idx/2; i++ )
   5.288 +					p_idx->idx[i] = p_idx->idx[2*i];
   5.289 +				p_idx->i_idx /= 2;
   5.290 +			}
   5.291 +		}
   5.292 +		else
   5.293 +		{
   5.294 +			p_idx->i_idx_max += 1000;
   5.295 +		}
   5.296 +	}
   5.297 +
   5.298 +	/* */
   5.299 +	p_idx->idx[p_idx->i_idx].i_time = i_time;
   5.300 +	p_idx->idx[p_idx->i_idx].i_offset = i_offset;
   5.301 +
   5.302 +	p_idx->i_idx++;
   5.303 +}
   5.304 +
   5.305 +static gint64 
   5.306 +gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time )
   5.307 +{
   5.308 +	nuv_demux_index *p_idx = nuv->index_entries;
   5.309 +
   5.310 +	g_return_val_if_fail( p_idx != NULL , i_time );
   5.311 +
   5.312 +	gint i_min = 0;
   5.313 +	gint i_max = p_idx->i_idx-1;
   5.314 +
   5.315 +	/* Empty index */
   5.316 +	if( p_idx->i_idx <= 0 )
   5.317 +		return -1;
   5.318 +
   5.319 +	/* Special border case */
   5.320 +	if( i_time <= p_idx->idx[0].i_time )
   5.321 +		return p_idx->idx[0].i_offset;
   5.322 +	if( i_time >= p_idx->idx[i_max].i_time )
   5.323 +		return p_idx->idx[i_max].i_offset;
   5.324 +
   5.325 +	/* Dicho */
   5.326 +	for( ;; )
   5.327 +	{
   5.328 +		gint i_med;
   5.329 +
   5.330 +		if( i_max - i_min <= 1 )
   5.331 +			break;
   5.332 +
   5.333 +		i_med = (i_min+i_max)/2;
   5.334 +		if( p_idx->idx[i_med].i_time < i_time )
   5.335 +			i_min = i_med;
   5.336 +		else if( p_idx->idx[i_med].i_time > i_time )
   5.337 +			i_max = i_med;
   5.338 +		else
   5.339 +			return p_idx->idx[i_med].i_offset;
   5.340 +	}
   5.341 +
   5.342 +	/* return nearest in time */
   5.343 +	if( i_time - p_idx->idx[i_min].i_time < p_idx->idx[i_max].i_time - i_time )
   5.344 +		return p_idx->idx[i_min].i_offset;
   5.345 +	else
   5.346 +		return p_idx->idx[i_max].i_offset;
   5.347 +}
   5.348 +
   5.349 +/*****************************************************************************
   5.350 + * Utils functions
   5.351 + *****************************************************************************/
   5.352 +
   5.353 +static gboolean
   5.354 +gst_nuv_demux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
   5.355 +{
   5.356 +  gboolean res = FALSE;
   5.357 +
   5.358 +  switch (GST_EVENT_TYPE (event)) {
   5.359 +    case GST_EVENT_NEWSEGMENT:
   5.360 +      res = TRUE;
   5.361 +      break;
   5.362 +    default:
   5.363 +      return gst_pad_event_default (sinkpad, event);
   5.364 +      break;
   5.365 +  }
   5.366 +
   5.367 +  gst_event_unref (event);
   5.368 +  return res;
   5.369 +}
   5.370 +
   5.371 +/* HeaderLoad:
   5.372 + */
   5.373 +static GstFlowReturn
   5.374 +gst_nuv_demux_header_load (GstNuvDemux * nuv, nuv_header ** h_ret)
   5.375 +{
   5.376 +  GstBuffer *buffer = NULL;
   5.377 +  GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 72, TRUE, &buffer);
   5.378 +
   5.379 +  if (res != GST_FLOW_OK)
   5.380 +    return res;
   5.381 +
   5.382 +  nuv_header *h = g_new0 (nuv_header, 1);
   5.383 +
   5.384 +  memcpy (h->id, buffer->data, 12);
   5.385 +  memcpy (h->version, buffer->data + 12, 5);
   5.386 +  h->i_width = GST_READ_UINT32_LE (&buffer->data[20]);
   5.387 +  h->i_height = GST_READ_UINT32_LE (&buffer->data[24]);
   5.388 +  h->i_width_desired = GST_READ_UINT32_LE (&buffer->data[28]);
   5.389 +  h->i_height_desired = GST_READ_UINT32_LE (&buffer->data[32]);
   5.390 +  h->i_mode = buffer->data[36];
   5.391 +  h->d_aspect = READ_DOUBLE_FROM_LE (&buffer->data[40]);
   5.392 +  h->d_fps = READ_DOUBLE_FROM_LE (&buffer->data[48]);
   5.393 +  h->i_video_blocks = GST_READ_UINT32_LE (&buffer->data[56]);
   5.394 +  h->i_audio_blocks = GST_READ_UINT32_LE (&buffer->data[60]);
   5.395 +  h->i_text_blocks = GST_READ_UINT32_LE (&buffer->data[64]);
   5.396 +  h->i_keyframe_distance = GST_READ_UINT32_LE (&buffer->data[68]);
   5.397 +
   5.398 +  GST_DEBUG_OBJECT (nuv,
   5.399 +      "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d", h->id,
   5.400 +      h->version, h->i_width, h->i_height, h->d_aspect, h->d_fps,
   5.401 +      h->i_video_blocks, h->i_audio_blocks, h->i_text_blocks,
   5.402 +      h->i_keyframe_distance);
   5.403 +
   5.404 +  *h_ret = h;
   5.405 +  gst_buffer_unref (buffer);
   5.406 +  return res;
   5.407 +}
   5.408 +
   5.409 +static GstFlowReturn
   5.410 +gst_nuv_demux_stream_header_data (GstNuvDemux * nuv)
   5.411 +{
   5.412 +  GstFlowReturn res = gst_nuv_demux_header_load (nuv, &nuv->h);
   5.413 +
   5.414 +  if (res == GST_FLOW_OK)
   5.415 +    nuv->state = GST_NUV_DEMUX_EXTRA_DATA;
   5.416 +  return res;
   5.417 +}
   5.418 +
   5.419 +/*
   5.420 + * Read NUV file tag
   5.421 + */
   5.422 +static GstFlowReturn
   5.423 +gst_nuv_demux_stream_file_header (GstNuvDemux * nuv)
   5.424 +{
   5.425 +  GstFlowReturn res = GST_FLOW_OK;
   5.426 +  GstBuffer *file_header = NULL;
   5.427 +
   5.428 +  res = gst_nuv_demux_read_bytes (nuv, 12, FALSE, &file_header);
   5.429 +  if (res != GST_FLOW_OK) {
   5.430 +    return res;
   5.431 +  } else {
   5.432 +    if (strncmp ((gchar *) file_header->data, "MythTVVideo", 11) ||
   5.433 +        strncmp ((gchar *) file_header->data, "NuppelVideo", 11)) {
   5.434 +      nuv->state = GST_NUV_DEMUX_HEADER_DATA;
   5.435 +    } else {
   5.436 +      GST_DEBUG_OBJECT (nuv, "error parsing file header");
   5.437 +      nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   5.438 +      res = GST_FLOW_ERROR;
   5.439 +    }
   5.440 +  }
   5.441 +  if (file_header != NULL) {
   5.442 +    gst_buffer_unref (file_header);
   5.443 +  }
   5.444 +  return res;
   5.445 +}
   5.446 +
   5.447 +/* FrameHeaderLoad:
   5.448 + */
   5.449 +static GstFlowReturn
   5.450 +gst_nuv_demux_frame_header_load (GstNuvDemux * nuv, nuv_frame_header ** h_ret)
   5.451 +{
   5.452 +  unsigned char *data;
   5.453 +  nuv_frame_header *h;
   5.454 +  GstBuffer *buf = NULL;
   5.455 +
   5.456 +  GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 12, TRUE, &buf);
   5.457 +
   5.458 +  if (res != GST_FLOW_OK) {
   5.459 +    if (buf != NULL) {
   5.460 +      gst_buffer_unref (buf);
   5.461 +    }
   5.462 +    return res;
   5.463 +  }
   5.464 +
   5.465 +  h = g_new0 (nuv_frame_header, 1);
   5.466 +  data = buf->data;
   5.467 +
   5.468 +  h->i_type = data[0];
   5.469 +  h->i_compression = data[1];
   5.470 +  h->i_keyframe = data[2];
   5.471 +  h->i_filters = data[3];
   5.472 +
   5.473 +  h->i_timecode = GST_READ_UINT32_LE (&data[4]);
   5.474 +
   5.475 +
   5.476 +  h->i_length = GST_READ_UINT32_LE (&data[8]);
   5.477 +  GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
   5.478 +      h->i_type,
   5.479 +      h->i_compression ? h->i_compression : ' ',
   5.480 +      h->i_keyframe ? h->i_keyframe : ' ',
   5.481 +      h->i_filters, h->i_timecode, h->i_length);
   5.482 +
   5.483 +  *h_ret = h;
   5.484 +  gst_buffer_unref (buf);
   5.485 +  return GST_FLOW_OK;
   5.486 +}
   5.487 +
   5.488 +static GstFlowReturn
   5.489 +gst_nuv_demux_extended_header_load (GstNuvDemux * nuv,
   5.490 +    nuv_extended_header ** h_ret)
   5.491 +{
   5.492 +  unsigned char *data;
   5.493 +  GstBuffer *buff = NULL;
   5.494 +  nuv_extended_header *h;
   5.495 +
   5.496 +
   5.497 +  GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 512, TRUE, &buff);
   5.498 +
   5.499 +  if (res != GST_FLOW_OK) {
   5.500 +    if (buff != NULL) {
   5.501 +      gst_buffer_unref (buff);
   5.502 +    }
   5.503 +    return res;
   5.504 +  }
   5.505 +
   5.506 +  h = g_new0 (nuv_extended_header, 1);
   5.507 +  data = buff->data;
   5.508 +  h->i_version = GST_READ_UINT32_LE (&data[0]);
   5.509 +  h->i_video_fcc = GST_MAKE_FOURCC (data[4], data[5], data[6], data[7]);
   5.510 +  h->i_audio_fcc = GST_MAKE_FOURCC (data[8], data[9], data[10], data[11]);
   5.511 +  h->i_audio_sample_rate = GST_READ_UINT32_LE (&data[12]);
   5.512 +  h->i_audio_bits_per_sample = GST_READ_UINT32_LE (&data[16]);
   5.513 +  h->i_audio_channels = GST_READ_UINT32_LE (&data[20]);
   5.514 +  h->i_audio_compression_ratio = GST_READ_UINT32_LE (&data[24]);
   5.515 +  h->i_audio_quality = GST_READ_UINT32_LE (&data[28]);
   5.516 +  h->i_rtjpeg_quality = GST_READ_UINT32_LE (&data[32]);
   5.517 +  h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE (&data[36]);
   5.518 +  h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE (&data[40]);
   5.519 +  h->i_lavc_bitrate = GST_READ_UINT32_LE (&data[44]);
   5.520 +  h->i_lavc_qmin = GST_READ_UINT32_LE (&data[48]);
   5.521 +  h->i_lavc_qmin = GST_READ_UINT32_LE (&data[52]);
   5.522 +  h->i_lavc_maxqdiff = GST_READ_UINT32_LE (&data[56]);
   5.523 +  h->i_seekable_offset = GST_READ_UINT64_LE (&data[60]);
   5.524 +  h->i_keyframe_adjust_offset = GST_READ_UINT64_LE (&data[68]);
   5.525 +
   5.526 +  GST_DEBUG_OBJECT (nuv,
   5.527 +      "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d"
   5.528 +      "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld",
   5.529 +      h->i_version, (gchar *) & h->i_video_fcc, (gchar *) & h->i_audio_fcc,
   5.530 +      h->i_audio_sample_rate, h->i_audio_bits_per_sample, h->i_audio_channels,
   5.531 +      h->i_audio_compression_ratio, h->i_audio_quality, h->i_rtjpeg_quality,
   5.532 +      h->i_rtjpeg_luma_filter, h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate,
   5.533 +      h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff, h->i_seekable_offset,
   5.534 +      h->i_keyframe_adjust_offset);
   5.535 +
   5.536 +  *h_ret = h;
   5.537 +  gst_buffer_unref (buff);
   5.538 +  return res;
   5.539 +}
   5.540 +
   5.541 +static gboolean
   5.542 +gst_nuv_demux_handle_audio_src_event (GstPad * pad, GstEvent * event)
   5.543 +{
   5.544 +  gst_event_unref (event);
   5.545 +  return FALSE;
   5.546 +}
   5.547 +
   5.548 +static gboolean
   5.549 +gst_nuv_demux_handle_video_src_event (GstPad * pad, GstEvent * event)
   5.550 +{
   5.551 +  gst_event_unref (event);
   5.552 +  return FALSE;
   5.553 +}
   5.554 +
   5.555 +static void
   5.556 +gst_nuv_demux_create_pads (GstNuvDemux * nuv)
   5.557 +{
   5.558 +  if (nuv->h->i_video_blocks != 0) {
   5.559 +    GstCaps *video_caps = NULL;
   5.560 +
   5.561 +    nuv->src_video_pad =
   5.562 +        gst_pad_new_from_static_template (&video_src_template, "video_src");
   5.563 +
   5.564 +    video_caps = gst_caps_new_simple ("video/x-divx",
   5.565 +        "divxversion", G_TYPE_INT, 4,
   5.566 +        "width", G_TYPE_INT, nuv->h->i_width,
   5.567 +        "height", G_TYPE_INT, nuv->h->i_height,
   5.568 +        "framerate", GST_TYPE_FRACTION, (gint) (nuv->h->d_fps * 1000.0f), 1000,
   5.569 +        "pixel-aspect-ratio", GST_TYPE_FRACTION,
   5.570 +        (gint) (nuv->h->d_aspect * 1000.0f), 1000, NULL);
   5.571 +
   5.572 +    gst_pad_use_fixed_caps (nuv->src_video_pad);
   5.573 +    gst_pad_set_caps (nuv->src_video_pad, video_caps);
   5.574 +
   5.575 +    gst_pad_set_event_function (nuv->src_video_pad,
   5.576 +	    	gst_nuv_demux_handle_video_src_event);
   5.577 +    gst_pad_set_active (nuv->src_video_pad, TRUE);
   5.578 +    gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
   5.579 +
   5.580 +    gst_caps_unref (video_caps);
   5.581 +  }
   5.582 +
   5.583 +  if (nuv->h->i_audio_blocks != 0) {
   5.584 +    GstCaps *audio_caps = NULL;
   5.585 +
   5.586 +    nuv->src_audio_pad =
   5.587 +        gst_pad_new_from_static_template (&audio_src_template, "audio_src");
   5.588 +
   5.589 +    audio_caps = gst_caps_new_simple ("audio/mpeg",
   5.590 +        "rate", G_TYPE_INT, nuv->eh->i_audio_sample_rate,
   5.591 +        "format", GST_TYPE_FOURCC, nuv->eh->i_audio_fcc,
   5.592 +        "channels", G_TYPE_INT, nuv->eh->i_audio_channels,
   5.593 +        "mpegversion", G_TYPE_INT, nuv->eh->i_version, NULL);
   5.594 +
   5.595 +    gst_pad_use_fixed_caps (nuv->src_audio_pad);
   5.596 +    gst_pad_set_caps (nuv->src_audio_pad, audio_caps);
   5.597 +    
   5.598 +    gst_pad_set_event_function (nuv->src_audio_pad,
   5.599 +  		  gst_nuv_demux_handle_audio_src_event);
   5.600 +    gst_pad_set_active (nuv->src_audio_pad, TRUE);
   5.601 +    gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
   5.602 +
   5.603 +    gst_caps_unref (audio_caps);
   5.604 +  }
   5.605 +
   5.606 +  gst_element_no_more_pads (GST_ELEMENT (nuv));
   5.607 +}
   5.608 +
   5.609 +static GstFlowReturn
   5.610 +gst_nuv_demux_read_head_frame (GstNuvDemux * nuv)
   5.611 +{
   5.612 +  GstFlowReturn ret = GST_FLOW_OK;
   5.613 +
   5.614 +  ret = gst_nuv_demux_frame_header_load (nuv, &nuv->fh);
   5.615 +  if (ret != GST_FLOW_OK)
   5.616 +    return ret;
   5.617 +
   5.618 +  nuv->state = GST_NUV_DEMUX_MOVI;
   5.619 +  return ret;
   5.620 +}
   5.621 +
   5.622 +static GstFlowReturn
   5.623 +gst_nuv_demux_stream_data (GstNuvDemux * nuv)
   5.624 +{
   5.625 +  GstFlowReturn ret = GST_FLOW_OK;
   5.626 +  GstBuffer *buf = NULL;
   5.627 +  nuv_frame_header *h = nuv->fh;
   5.628 +  
   5.629 +  gint64 table_timecode = 0;
   5.630 +
   5.631 +  if (h->i_type == 'R')
   5.632 +    goto done;
   5.633 +    
   5.634 +  table_timecode = h->i_timecode;
   5.635 +
   5.636 +  /* append the frame's header timecode field, and the actual offset */
   5.637 +  if ( h->i_type == 'V' ) 
   5.638 +  	gst_nuv_demux_index_append( nuv, h->i_timecode, nuv->video_offset );
   5.639 +  else if ( h->i_type == 'A' ) 
   5.640 +  	gst_nuv_demux_index_append( nuv, h->i_timecode, nuv->audio_offset );  	
   5.641 + 
   5.642 +  if (h->i_length > 0) {
   5.643 +	  ret = gst_nuv_demux_read_bytes (nuv, h->i_length, TRUE, &buf);
   5.644 +	  if (ret != GST_FLOW_OK)
   5.645 +		  return ret;
   5.646 +
   5.647 +	  /* search for a valid timecode in the indexes list (find the nearest valid timecode) */
   5.648 +	  if ( h->i_timecode < 0 ) {
   5.649 +		  /* convert this actual timecode to a valid index in the timecode's table */
   5.650 +		  gint64 pos = gst_nuv_demux_index_convert_time( nuv, h->i_timecode );
   5.651 +
   5.652 +		  /* just get the timecode from the timecode's table */		  
   5.653 +		  table_timecode = nuv->index_entries->idx[pos].i_time * GST_MSECOND;
   5.654 +	  } else {  
   5.655 +			table_timecode = h->i_timecode * GST_MSECOND;
   5.656 +	  }
   5.657 +	  
   5.658 +	  GST_BUFFER_TIMESTAMP (buf) = table_timecode;
   5.659 +  }  
   5.660 +
   5.661 +  switch (h->i_type) {
   5.662 +    case 'V':
   5.663 +    {
   5.664 +      if (h->i_length == 0)
   5.665 +        break;
   5.666 +        
   5.667 +      if ( !gst_pad_is_linked( nuv->src_video_pad ) )
   5.668 +      	break;
   5.669 +      
   5.670 +      //GST_PAD_STREAM_LOCK(nuv->src_video_pad);
   5.671 +      
   5.672 +      GST_BUFFER_SIZE (buf) = h->i_length;
   5.673 +      gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_video_pad));
   5.674 +      ret = gst_pad_push (nuv->src_video_pad, buf);
   5.675 +      nuv->video_offset += h->i_length;
   5.676 +      
   5.677 +      //GST_PAD_STREAM_UNLOCK(nuv->src_video_pad);
   5.678 +      break;
   5.679 +    }
   5.680 +    case 'A':
   5.681 +    {
   5.682 +      if (h->i_length == 0)
   5.683 +        break;
   5.684 +        
   5.685 +      if ( !gst_pad_is_linked( nuv->src_audio_pad ) )
   5.686 +      	break;
   5.687 +        
   5.688 +      //GST_PAD_STREAM_LOCK(nuv->src_audio_pad);
   5.689 +      
   5.690 +      GST_BUFFER_SIZE (buf) = h->i_length;
   5.691 +      gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_audio_pad));
   5.692 +      ret = gst_pad_push (nuv->src_audio_pad, buf);
   5.693 +      nuv->audio_offset += h->i_length;
   5.694 +      
   5.695 +      //GST_PAD_STREAM_UNLOCK(nuv->src_audio_pad);
   5.696 +      break;
   5.697 +    }
   5.698 +    case 'S':
   5.699 +    {
   5.700 +      switch (h->i_compression) {
   5.701 +        case 'V':
   5.702 +		      if ( !gst_pad_is_linked( nuv->src_video_pad ) )
   5.703 +		      	break;
   5.704 +
   5.705 +        	//GST_PAD_STREAM_LOCK(nuv->src_video_pad);
   5.706 +          gst_pad_push_event (nuv->src_video_pad,
   5.707 +              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, table_timecode, 
   5.708 +              		GST_CLOCK_TIME_NONE, 0));
   5.709 +          //GST_PAD_STREAM_UNLOCK(nuv->src_video_pad);
   5.710 +          break;
   5.711 +        case 'A':        
   5.712 +		      if ( !gst_pad_is_linked( nuv->src_audio_pad ) )
   5.713 +		      	break;
   5.714 +
   5.715 +        	//GST_PAD_STREAM_LOCK(nuv->src_audio_pad);
   5.716 +          gst_pad_push_event (nuv->src_audio_pad,
   5.717 +              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, table_timecode, 
   5.718 +              		GST_CLOCK_TIME_NONE, 0));
   5.719 +          //GST_PAD_STREAM_UNLOCK(nuv->src_audio_pad);
   5.720 +          break;
   5.721 +        default:
   5.722 +          break;
   5.723 +      }
   5.724 +    }
   5.725 +    default:
   5.726 +      if (buf != NULL)
   5.727 +        gst_buffer_unref (buf);
   5.728 +
   5.729 +      break;
   5.730 +  }
   5.731 +
   5.732 +done:
   5.733 +  nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   5.734 +  g_free (nuv->fh);
   5.735 +  nuv->fh = NULL;
   5.736 +  return ret;
   5.737 +}
   5.738 +
   5.739 +static GstFlowReturn
   5.740 +gst_nuv_demux_stream_mpeg_data (GstNuvDemux * nuv)
   5.741 +{
   5.742 +  GstFlowReturn ret = GST_FLOW_OK;
   5.743 +
   5.744 +  /* ffmpeg extra data */
   5.745 +  ret =
   5.746 +      gst_nuv_demux_read_bytes (nuv, nuv->mpeg_data_size, TRUE,
   5.747 +      &nuv->mpeg_buffer);
   5.748 +  if (ret != GST_FLOW_OK) {
   5.749 +    return ret; //GST_FLOW_ERROR;
   5.750 +  }
   5.751 +  GST_BUFFER_SIZE (nuv->mpeg_buffer) = nuv->mpeg_data_size;
   5.752 +  nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   5.753 +  return ret;
   5.754 +}
   5.755 +
   5.756 +static GstFlowReturn
   5.757 +gst_nuv_demux_stream_extra_data (GstNuvDemux * nuv)
   5.758 +{
   5.759 +  GstFlowReturn ret = GST_FLOW_OK;
   5.760 +
   5.761 +  /* Load 'D' */
   5.762 +  nuv_frame_header *h;
   5.763 +
   5.764 +  ret = gst_nuv_demux_frame_header_load (nuv, &h);
   5.765 +  if (ret != GST_FLOW_OK)
   5.766 +    return ret;
   5.767 +
   5.768 +  if (h->i_type != 'D') {
   5.769 +    g_free (h);
   5.770 +    return GST_FLOW_ERROR;
   5.771 +  }
   5.772 +
   5.773 +  if (h->i_length > 0) {
   5.774 +    if (h->i_compression == 'F') {
   5.775 +      nuv->state = GST_NUV_DEMUX_MPEG_DATA;
   5.776 +    } else {
   5.777 +      g_free (h);
   5.778 +      return GST_FLOW_ERROR;
   5.779 +    }
   5.780 +  } else {
   5.781 +    nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   5.782 +  }
   5.783 +
   5.784 +  g_free (h);
   5.785 +  h = NULL;
   5.786 +  return ret;
   5.787 +}
   5.788 +
   5.789 +static GstFlowReturn
   5.790 +gst_nuv_demux_stream_extend_header_data (GstNuvDemux * nuv)
   5.791 +{
   5.792 +  GstFlowReturn ret = GST_FLOW_OK;
   5.793 +
   5.794 +  ret = gst_nuv_demux_extended_header_load (nuv, &nuv->eh);
   5.795 +  if (ret != GST_FLOW_OK)
   5.796 +    return ret;
   5.797 +
   5.798 +  gst_nuv_demux_create_pads (nuv);
   5.799 +  nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   5.800 +  return ret;
   5.801 +}
   5.802 +
   5.803 +static GstFlowReturn
   5.804 +gst_nuv_demux_stream_extend_header (GstNuvDemux * nuv)
   5.805 +{
   5.806 +  GstBuffer *buf = NULL;
   5.807 +  GstFlowReturn res = GST_FLOW_OK;
   5.808 +
   5.809 +  res = gst_nuv_demux_read_bytes (nuv, 1, FALSE, &buf);
   5.810 +  if (res != GST_FLOW_OK) {
   5.811 +    if (buf != NULL) {
   5.812 +      gst_buffer_unref (buf);
   5.813 +    }
   5.814 +    return res;
   5.815 +  }
   5.816 +
   5.817 +  if (buf->data[0] == 'X') {
   5.818 +    gst_buffer_unref (buf);
   5.819 +    buf = NULL;
   5.820 +    nuv_frame_header *h = NULL;
   5.821 +
   5.822 +    res = gst_nuv_demux_frame_header_load (nuv, &h);
   5.823 +    if (res != GST_FLOW_OK)
   5.824 +      return res;
   5.825 +
   5.826 +    if (h->i_length != 512) {
   5.827 +      g_free (h);
   5.828 +      return GST_FLOW_ERROR;
   5.829 +    }
   5.830 +    g_free (h);
   5.831 +    h = NULL;
   5.832 +    nuv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
   5.833 +  } else {
   5.834 +    nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   5.835 +    g_object_unref (buf);
   5.836 +    GST_ELEMENT_WARNING (nuv, STREAM, FAILED,
   5.837 +        (_("incomplete NUV support")), ("incomplete NUV support"));
   5.838 +    return GST_FLOW_ERROR;
   5.839 +  }
   5.840 +  return res;
   5.841 +}
   5.842 +
   5.843 +static GstFlowReturn
   5.844 +gst_nuv_demux_play (GstPad * pad)
   5.845 +{
   5.846 +  GstFlowReturn res = GST_FLOW_OK;
   5.847 +  GstNuvDemux *nuv = GST_NUV_DEMUX (GST_PAD_PARENT (pad));
   5.848 +
   5.849 +  switch (nuv->state) {
   5.850 +    case GST_NUV_DEMUX_START:
   5.851 +      res = gst_nuv_demux_stream_file_header (nuv);
   5.852 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   5.853 +        goto pause;
   5.854 +      }
   5.855 +      if (nuv->state != GST_NUV_DEMUX_HEADER_DATA)
   5.856 +        break;
   5.857 +
   5.858 +    case GST_NUV_DEMUX_HEADER_DATA:
   5.859 +      res = gst_nuv_demux_stream_header_data (nuv);
   5.860 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   5.861 +        goto pause;
   5.862 +      }
   5.863 +      if (nuv->state != GST_NUV_DEMUX_EXTRA_DATA)
   5.864 +        break;
   5.865 +
   5.866 +    case GST_NUV_DEMUX_EXTRA_DATA:
   5.867 +      res = gst_nuv_demux_stream_extra_data (nuv);
   5.868 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   5.869 +        goto pause;
   5.870 +      }
   5.871 +      if (nuv->state != GST_NUV_DEMUX_MPEG_DATA)
   5.872 +        break;
   5.873 +
   5.874 +    case GST_NUV_DEMUX_MPEG_DATA:
   5.875 +      res = gst_nuv_demux_stream_mpeg_data (nuv);
   5.876 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   5.877 +        goto pause;
   5.878 +      }
   5.879 +
   5.880 +      if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER)
   5.881 +        break;
   5.882 +
   5.883 +    case GST_NUV_DEMUX_EXTEND_HEADER:
   5.884 +      res = gst_nuv_demux_stream_extend_header (nuv);
   5.885 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   5.886 +        goto pause;
   5.887 +      }
   5.888 +      if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER_DATA)
   5.889 +        break;
   5.890 +
   5.891 +    case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
   5.892 +      res = gst_nuv_demux_stream_extend_header_data (nuv);
   5.893 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   5.894 +        goto pause;
   5.895 +      }
   5.896 +
   5.897 +      if (nuv->state != GST_NUV_DEMUX_FRAME_HEADER)
   5.898 +        break;
   5.899 +
   5.900 +    case GST_NUV_DEMUX_FRAME_HEADER:
   5.901 +      res = gst_nuv_demux_read_head_frame (nuv);
   5.902 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   5.903 +        goto pause;
   5.904 +      }
   5.905 +      if (nuv->state != GST_NUV_DEMUX_MOVI)
   5.906 +        break;
   5.907 +
   5.908 +    case GST_NUV_DEMUX_MOVI:
   5.909 +      res = gst_nuv_demux_stream_data (nuv);
   5.910 +      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA) && (res != GST_FLOW_CUSTOM_ERROR)) {
   5.911 +        goto pause;
   5.912 +      }
   5.913 +      break;
   5.914 +    case GST_NUV_DEMUX_INVALID_DATA:
   5.915 +      goto pause;
   5.916 +      break;
   5.917 +    default:
   5.918 +      g_assert_not_reached ();
   5.919 +  }
   5.920 +
   5.921 +  GST_DEBUG_OBJECT (nuv, "state: %d res:%s", nuv->state,
   5.922 +      gst_flow_get_name (res));
   5.923 +
   5.924 +  return GST_FLOW_OK;
   5.925 +
   5.926 +pause:
   5.927 +  GST_LOG_OBJECT (nuv, "pausing task, reason %s", gst_flow_get_name (res));
   5.928 +  gst_pad_pause_task (nuv->sinkpad);
   5.929 +  if (GST_FLOW_IS_FATAL (res)) {
   5.930 +    GST_ELEMENT_ERROR (nuv, STREAM, FAILED,
   5.931 +        (_("Internal data stream error.")),
   5.932 +        ("streaming stopped, reason %s", gst_flow_get_name (res)));
   5.933 +
   5.934 +    gst_nuv_demux_send_eos (nuv);
   5.935 +  }
   5.936 +  return res;
   5.937 +}
   5.938 +
   5.939 +static void
   5.940 +gst_nuv_demux_send_eos (GstNuvDemux * nuv)
   5.941 +{
   5.942 +  gst_element_post_message (GST_ELEMENT (nuv),
   5.943 +      gst_message_new_segment_done (GST_OBJECT (nuv), GST_FORMAT_TIME, -1));
   5.944 +
   5.945 +  if (nuv->src_video_pad)
   5.946 +    gst_pad_push_event (nuv->src_video_pad, gst_event_new_eos ());
   5.947 +  if (nuv->src_audio_pad)
   5.948 +    gst_pad_push_event (nuv->src_audio_pad, gst_event_new_eos ());
   5.949 +}
   5.950 +
   5.951 +static GstFlowReturn
   5.952 +gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size, gboolean move,
   5.953 +    GstBuffer ** buffer)
   5.954 +{
   5.955 +  GstFlowReturn ret = GST_FLOW_OK;
   5.956 +
   5.957 +  if (size == 0) {
   5.958 +    *buffer = gst_buffer_new ();
   5.959 +    return ret;
   5.960 +  }
   5.961 +  
   5.962 +  if (nuv->mode == 0) {
   5.963 +    ret = gst_pad_pull_range (nuv->sinkpad, nuv->offset, size, buffer);
   5.964 +    if (ret == GST_FLOW_OK) {
   5.965 +    		if (move) {
   5.966 +					nuv->offset += size;
   5.967 +				}    	
   5.968 +      /* got eos */
   5.969 +    } else if (ret == GST_FLOW_UNEXPECTED) {
   5.970 +      gst_nuv_demux_send_eos (nuv);
   5.971 +      return GST_FLOW_WRONG_STATE;
   5.972 +    }
   5.973 +  } else {
   5.974 +    if (gst_adapter_available (nuv->adapter) < size)
   5.975 +      return GST_FLOW_ERROR_NO_DATA;
   5.976 +
   5.977 +    if (move) {
   5.978 +      *buffer = gst_adapter_take_buffer (nuv->adapter, size);
   5.979 +    } else {
   5.980 +      guint8 *data = NULL;
   5.981 +
   5.982 +      data = (guint8 *) gst_adapter_peek (nuv->adapter, size);
   5.983 +      *buffer = gst_buffer_new ();
   5.984 +      gst_buffer_set_data (*buffer, data, size);
   5.985 +    }
   5.986 +  }
   5.987 +  
   5.988 +	
   5.989 +  return ret;
   5.990 +}
   5.991 +
   5.992 +static gboolean
   5.993 +gst_nuv_demux_sink_activate (GstPad * sinkpad)
   5.994 +{
   5.995 +  gboolean res = TRUE;
   5.996 +  GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
   5.997 +
   5.998 +  if (gst_pad_check_pull_range (sinkpad)) {
   5.999 +    nuv->mode = 0;
  5.1000 +    if (nuv->adapter) {
  5.1001 +      gst_adapter_clear (nuv->adapter);
  5.1002 +      g_object_unref (nuv->adapter);
  5.1003 +      nuv->adapter = NULL;
  5.1004 +    }
  5.1005 +    res = gst_pad_activate_pull (sinkpad, TRUE);
  5.1006 +  } else {
  5.1007 +    nuv->mode = 1;
  5.1008 +    if (nuv->adapter) {
  5.1009 +      gst_adapter_clear (nuv->adapter);
  5.1010 +    } else {
  5.1011 +      nuv->adapter = gst_adapter_new ();
  5.1012 +    }
  5.1013 +    res = gst_pad_activate_push (sinkpad, TRUE);
  5.1014 +  }
  5.1015 +
  5.1016 +  g_object_unref (nuv);
  5.1017 +  return res;
  5.1018 +}
  5.1019 +
  5.1020 +static gboolean
  5.1021 +gst_nuv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
  5.1022 +{
  5.1023 +  GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
  5.1024 +
  5.1025 +  if (active) {
  5.1026 +    gst_pad_start_task (sinkpad, (GstTaskFunction) gst_nuv_demux_loop, sinkpad);
  5.1027 +  } else {
  5.1028 +    gst_pad_stop_task (sinkpad);
  5.1029 +  }
  5.1030 +  gst_object_unref (nuv);
  5.1031 +
  5.1032 +  return TRUE;
  5.1033 +}
  5.1034 +
  5.1035 +static GstFlowReturn
  5.1036 +gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf)
  5.1037 +{
  5.1038 +  GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
  5.1039 +
  5.1040 +  gst_adapter_push (nuv->adapter, buf);
  5.1041 +
  5.1042 +  return gst_nuv_demux_play (pad);
  5.1043 +}
  5.1044 +
  5.1045 +static void
  5.1046 +gst_nuv_demux_loop (GstPad * pad)
  5.1047 +{
  5.1048 +  gst_nuv_demux_play (pad);
  5.1049 +}
  5.1050 +
  5.1051 +static void
  5.1052 +gst_nuv_demux_reset (GstNuvDemux * nuv)
  5.1053 +{
  5.1054 +  nuv->state = GST_NUV_DEMUX_START;
  5.1055 +  nuv->mode = 0;
  5.1056 +  nuv->offset = 0;
  5.1057 +  nuv->video_offset = 0;
  5.1058 +  nuv->audio_offset = 0;
  5.1059 +
  5.1060 +  if (nuv->adapter != NULL)
  5.1061 +    gst_adapter_clear (nuv->adapter);
  5.1062 +
  5.1063 +  if (nuv->mpeg_buffer != NULL) {
  5.1064 +    gst_buffer_unref (nuv->mpeg_buffer);
  5.1065 +    nuv->mpeg_buffer = NULL;
  5.1066 +  }
  5.1067 +
  5.1068 +  g_free (nuv->h);
  5.1069 +  nuv->h = NULL;
  5.1070 +
  5.1071 +  g_free (nuv->eh);
  5.1072 +  nuv->eh = NULL;
  5.1073 +
  5.1074 +  g_free (nuv->fh);
  5.1075 +  nuv->fh = NULL;
  5.1076 +}
  5.1077 +
  5.1078 +static void
  5.1079 +gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv)
  5.1080 +{
  5.1081 +  if (nuv->src_video_pad) {
  5.1082 +    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
  5.1083 +    nuv->src_video_pad = NULL;
  5.1084 +  }
  5.1085 +
  5.1086 +  if (nuv->src_audio_pad) {
  5.1087 +    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
  5.1088 +    nuv->src_audio_pad = NULL;
  5.1089 +  }
  5.1090 +}
  5.1091 +
  5.1092 +static GstStateChangeReturn
  5.1093 +gst_nuv_demux_change_state (GstElement * element, GstStateChange transition)
  5.1094 +{
  5.1095 +  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  5.1096 +
  5.1097 +  switch (transition) {
  5.1098 +    case GST_STATE_CHANGE_READY_TO_PAUSED:
  5.1099 +      break;
  5.1100 +    default:
  5.1101 +      break;
  5.1102 +  }
  5.1103 +
  5.1104 +  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  5.1105 +  if (ret == GST_STATE_CHANGE_FAILURE)
  5.1106 +    goto done;
  5.1107 +
  5.1108 +  switch (transition) {
  5.1109 +    case GST_STATE_CHANGE_PAUSED_TO_READY:
  5.1110 +      gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (element));
  5.1111 +      gst_nuv_demux_reset (GST_NUV_DEMUX (element));
  5.1112 +      break;
  5.1113 +    default:
  5.1114 +      break;
  5.1115 +  }
  5.1116 +
  5.1117 +done:
  5.1118 +  return ret;
  5.1119 +}
  5.1120 +
  5.1121 +static gboolean
  5.1122 +plugin_init (GstPlugin * plugin)
  5.1123 +{
  5.1124 +#ifdef ENABLE_NLS
  5.1125 +  setlocale (LC_ALL, "");
  5.1126 +  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  5.1127 +#endif /* ENABLE_NLS */
  5.1128 +
  5.1129 +  if (!gst_element_register (plugin, "nuvdemux", GST_RANK_SECONDARY,
  5.1130 +          GST_TYPE_NUV_DEMUX)) {
  5.1131 +    return FALSE;
  5.1132 +  }
  5.1133 +  return TRUE;
  5.1134 +}
  5.1135 +
  5.1136 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
  5.1137 +    GST_VERSION_MINOR,
  5.1138 +    "nuvdemux",
  5.1139 +    "Demuxes and muxes audio and video",
  5.1140 +    plugin_init, VERSION, "LGPL", "NuvDemux", "")
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.h	Thu Nov 09 19:45:27 2006 +0000
     6.3 @@ -0,0 +1,198 @@
     6.4 +/* GStreamer
     6.5 + * Copyright (C) <2006> Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
     6.6 + *                      Rosfran Borges <rosfran.borges@indt.org.br>
     6.7 + *
     6.8 + * This library is free software; you can redistribute it and/or
     6.9 + * modify it under the terms of the GNU Library General Public
    6.10 + * License as published by the Free Software Foundation; either
    6.11 + * version 2 of the License, or (at your option) any later version.
    6.12 + *
    6.13 + * This library is distributed in the hope that it will be useful,
    6.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    6.16 + * Library General Public License for more details.
    6.17 + *
    6.18 + * You should have received a copy of the GNU Library General Public
    6.19 + * License along with this library; if not, write to the
    6.20 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    6.21 + * Boston, MA 02111-1307, USA.
    6.22 + */
    6.23 +
    6.24 +#ifndef __GST_NUV_DEMUX_H__
    6.25 +#define __GST_NUV_DEMUX_H__
    6.26 +
    6.27 +#include <gst/gst.h>
    6.28 +
    6.29 +#include <gst/base/gstadapter.h>
    6.30 +
    6.31 +G_BEGIN_DECLS
    6.32 +
    6.33 +#define GST_TYPE_NUV_DEMUX \
    6.34 +  (gst_nuv_demux_get_type ())
    6.35 +#define GST_NUV_DEMUX(obj) \
    6.36 +  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_NUV_DEMUX, GstNuvDemux))
    6.37 +#define GST_NUV_DEMUX_CLASS(klass) \
    6.38 +  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_NUV_DEMUX, GstNuvDemuxClass))
    6.39 +#define GST_IS_NUV_DEMUX(obj) \
    6.40 +  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_NUV_DEMUX))
    6.41 +#define GST_IS_NUV_DEMUX_CLASS(klass) \
    6.42 +  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_NUV_DEMUX))
    6.43 +
    6.44 +#define DEMUX_INDEX_SIZE_MAX (100000)
    6.45 +
    6.46 +/* Indexes (timecodes/offsets) conversion structures */
    6.47 +typedef struct
    6.48 +{
    6.49 +    gint64 i_time;
    6.50 +    gint64 i_offset;
    6.51 +
    6.52 +} nuv_demux_index_entry;
    6.53 +
    6.54 +typedef struct
    6.55 +{
    6.56 +    gint i_idx;
    6.57 +    gint i_idx_max;
    6.58 +
    6.59 +    nuv_demux_index_entry idx[DEMUX_INDEX_SIZE_MAX];
    6.60 +} nuv_demux_index;
    6.61 +
    6.62 +/* */
    6.63 +typedef struct
    6.64 +{
    6.65 +    gchar id[12];       /* "NuppelVideo\0" or "MythTVVideo\0" */
    6.66 +    gchar version[5];    /* "x.xx\0" */
    6.67 +
    6.68 +    gint  i_width;
    6.69 +    gint  i_height;
    6.70 +    gint  i_width_desired;
    6.71 +    gint  i_height_desired;
    6.72 +
    6.73 +    gchar i_mode;            /* P progressive, I interlaced */
    6.74 +
    6.75 +    gdouble  d_aspect;       /* 1.0 squared pixel */
    6.76 +    gdouble  d_fps;
    6.77 +
    6.78 +    gint     i_video_blocks; /* 0 no video, -1 unknown */
    6.79 +    gint     i_audio_blocks;
    6.80 +    gint     i_text_blocks;
    6.81 +
    6.82 +    gint     i_keyframe_distance;
    6.83 +
    6.84 +} nuv_header;
    6.85 +
    6.86 +typedef struct
    6.87 +{
    6.88 +    gchar i_type;        /* A: audio, V: video, S: sync; T: test
    6.89 +                           R: Seekpoint (string:RTjjjjjjjj)
    6.90 +                           D: Extra data for codec */
    6.91 +    gchar i_compression; /* V: 0 uncompressed
    6.92 +                              1 RTJpeg
    6.93 +                              2 RTJpeg+lzo
    6.94 +                              N black frame
    6.95 +                              L copy last
    6.96 +                           A: 0 uncompressed (44100 1-bits, 2ch)
    6.97 +                              1 lzo
    6.98 +                              2 layer 2
    6.99 +                              3 layer 3
   6.100 +                              F flac
   6.101 +                              S shorten
   6.102 +                              N null frame loudless
   6.103 +                              L copy last
   6.104 +                            S: B audio and vdeo sync point
   6.105 +                               A audio sync info (timecode == effective
   6.106 +                                    dsp frequency*100)
   6.107 +                               V next video sync (timecode == next video
   6.108 +                                    frame num)
   6.109 +                               S audio,video,text correlation */
   6.110 +    gchar i_keyframe;    /* 0 keyframe, else no no key frame */
   6.111 +    guint8 i_filters;  /* 0x01: gauss 5 pixel (8,2,2,2,2)/16
   6.112 +                           0x02: gauss 5 pixel (8,1,1,1,1)/12
   6.113 +                           0x04: cartoon filter */
   6.114 +
   6.115 +    gint32 i_timecode;     /* ms */
   6.116 +
   6.117 +    gint i_length;       /* V,A,T: length of following data
   6.118 +                           S: length of packet correl */
   6.119 +} nuv_frame_header;
   6.120 +
   6.121 +/* FIXME Not sure of this one */
   6.122 +typedef struct
   6.123 +{
   6.124 +    gint             i_version;
   6.125 +    guint32		     i_video_fcc;
   6.126 +
   6.127 +    guint32		     i_audio_fcc;
   6.128 +    gint             i_audio_sample_rate;
   6.129 +    gint             i_audio_bits_per_sample;
   6.130 +    gint             i_audio_channels;
   6.131 +    gint             i_audio_compression_ratio;
   6.132 +    gint             i_audio_quality;
   6.133 +    gint             i_rtjpeg_quality;
   6.134 +    gint             i_rtjpeg_luma_filter;
   6.135 +    gint             i_rtjpeg_chroma_filter;
   6.136 +    gint             i_lavc_bitrate;
   6.137 +    gint             i_lavc_qmin;
   6.138 +    gint             i_lavc_qmax;
   6.139 +    gint             i_lavc_maxqdiff;
   6.140 +    gint64         	 i_seekable_offset;
   6.141 +    gint64           i_keyframe_adjust_offset;
   6.142 +
   6.143 +} nuv_extended_header;
   6.144 +
   6.145 +typedef enum {
   6.146 +  GST_NUV_DEMUX_START,
   6.147 +  GST_NUV_DEMUX_HEADER_DATA,
   6.148 +  GST_NUV_DEMUX_EXTRA_DATA,
   6.149 +  GST_NUV_DEMUX_MPEG_DATA,
   6.150 +  GST_NUV_DEMUX_EXTEND_HEADER,
   6.151 +  GST_NUV_DEMUX_EXTEND_HEADER_DATA,
   6.152 +  GST_NUV_DEMUX_FRAME_HEADER,
   6.153 +  GST_NUV_DEMUX_MOVI,
   6.154 +  GST_NUV_DEMUX_INVALID_DATA
   6.155 +} GstNuvDemuxState;
   6.156 +
   6.157 +typedef struct _GstNuvDemux {
   6.158 +  GstElement     parent;
   6.159 +
   6.160 +  guint         mode;
   6.161 +  GstAdapter    *adapter; 
   6.162 +  guint64       video_offset;
   6.163 +  guint64       audio_offset;
   6.164 +
   6.165 +  /* pads */
   6.166 +  
   6.167 +  GstPad        *sinkpad;
   6.168 +  GstPad        *src_video_pad;  
   6.169 +  GstPad        *src_audio_pad;
   6.170 +  gboolean      first_video;
   6.171 +  gboolean      first_audio;
   6.172 +
   6.173 +  /* NUV decoding state */
   6.174 +  GstNuvDemuxState state;
   6.175 +  guint64        offset;
   6.176 +
   6.177 +  /* Mpeg ExtraData */
   6.178 +  guint64       mpeg_data_size;
   6.179 +  GstBuffer     *mpeg_buffer;
   6.180 +  
   6.181 +  nuv_header *h;
   6.182 +  nuv_extended_header *eh;
   6.183 +  nuv_frame_header *fh;
   6.184 +  
   6.185 +  /* index */
   6.186 +  nuv_demux_index *index_entries;
   6.187 +  guint          index_size;
   6.188 +  guint64        index_offset;
   6.189 +  guint          current_entry;
   6.190 +
   6.191 +} GstNuvDemux;
   6.192 +
   6.193 +typedef struct _GstNuvDemuxClass {
   6.194 +  GstElementClass parent_class;
   6.195 +} GstNuvDemuxClass;
   6.196 +
   6.197 +GType           gst_nuv_demux_get_type          (void);
   6.198 +
   6.199 +G_END_DECLS
   6.200 +
   6.201 +#endif /* __GST_NUV_DEMUX_H__ */
     7.1 --- a/gst-plugins-nuvdemux/src/Makefile.am	Thu Nov 09 19:12:55 2006 +0000
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,20 +0,0 @@
     7.4 -plugin_LTLIBRARIES = libgstnuvdemux.la
     7.5 -
     7.6 -libgstnuvdemux_la_SOURCES =	\
     7.7 -	gstnuvdemux.c 
     7.8 -
     7.9 -libgstnuvdemux_la_CFLAGS = \
    7.10 -	$(GST_CFLAGS) \
    7.11 -	$(GST_PLUGINS_BASE_CFLAGS)
    7.12 -
    7.13 -libgstnuvdemux_la_LIBADD = \
    7.14 -	$(GST_LIBS_LIBS)
    7.15 -
    7.16 -libgstnuvdemux_la_LDFLAGS = \
    7.17 -	$(GST_PLUGIN_LDFLAGS) \
    7.18 -	$(GST_BASE_LIBS) \
    7.19 -	$(GST_PLUGINS_BASE_LIBS)
    7.20 -
    7.21 -noinst_HEADERS = \
    7.22 -	gstnuvdemux.h 
    7.23 -
     8.1 --- a/gst-plugins-nuvdemux/src/gstnuvdemux.c	Thu Nov 09 19:12:55 2006 +0000
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,1137 +0,0 @@
     8.4 -/* GStreamer
     8.5 - * Copyright (C) <2006> Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
     8.6 - *                      Rosfran Borges <rosfran.borges@indt.org.br>
     8.7 - *
     8.8 - * This library is free software; you can redistribute it and/or
     8.9 - * modify it under the terms of the GNU Library General Public
    8.10 - * License as published by the Free Software Foundation; either
    8.11 - * version 2 of the License, or (at your option) any later version.
    8.12 - *
    8.13 - * This library is distributed in the hope that it will be useful,
    8.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    8.16 - * Library General Public License for more details.
    8.17 - *
    8.18 - * You should have received a copy of the GNU Library General Public
    8.19 - * License along with this library; if not, write to the
    8.20 - * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    8.21 - * Boston, MA 02111-1307, USA.
    8.22 - */
    8.23 -/* Element-Checklist-Version: 5 */
    8.24 -
    8.25 -/**
    8.26 - * SECTION:element-nuvdemux
    8.27 - *
    8.28 - * <refsect2>
    8.29 - * <para>
    8.30 - * Demuxes an .nuv file into raw or compressed audio and/or video streams.
    8.31 - * </para>
    8.32 - * <para>
    8.33 - * This element currently only supports pull-based scheduling.
    8.34 - * </para>
    8.35 - * <title>Example launch line</title>
    8.36 - * <para>
    8.37 - * <programlisting>
    8.38 - * gst-launch filesrc test.nuv ! nuvdemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
    8.39 - * </programlisting>
    8.40 - * Play (parse and decode) an .nuv file and try to output it to
    8.41 - * an automatically detected soundcard and videosink. If the NUV file contains
    8.42 - * compressed audio or video data, this will only work if you have the
    8.43 - * right decoder elements/plugins installed.
    8.44 - * </para>
    8.45 - * </refsect2>
    8.46 - *
    8.47 - */
    8.48 -
    8.49 -#ifdef HAVE_CONFIG_H
    8.50 -#include "config.h"
    8.51 -#endif
    8.52 -
    8.53 -#include <gst/gst.h>
    8.54 -#include <gst/gsterror.h>
    8.55 -#include <gst/gstplugin.h>
    8.56 -#include <string.h>
    8.57 -
    8.58 -#include "glib/gi18n.h"
    8.59 -#include "gstnuvdemux.h"
    8.60 -
    8.61 -GST_DEBUG_CATEGORY_STATIC (nuvdemux_debug);
    8.62 -#define GST_CAT_DEFAULT nuvdemux_debug
    8.63 -
    8.64 -
    8.65 -#define GST_FLOW_ERROR_NO_DATA  -101
    8.66 -
    8.67 -GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT);
    8.68 -
    8.69 -static const GstElementDetails gst_nuv_demux_details =
    8.70 -GST_ELEMENT_DETAILS ("Nuv demuxer",
    8.71 -    "Codec/Demuxer",
    8.72 -    "Demultiplex a .nuv file into audio and video",
    8.73 -    "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
    8.74 -    "Rosfran Borges <rosfran.borges@indt.org.br>");
    8.75 -
    8.76 -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
    8.77 -    GST_PAD_SINK,
    8.78 -    GST_PAD_ALWAYS,
    8.79 -    GST_STATIC_CAPS ("video/x-nuv"));
    8.80 -
    8.81 -static GstStaticPadTemplate audio_src_template =
    8.82 -GST_STATIC_PAD_TEMPLATE ("audio_src",
    8.83 -    GST_PAD_SRC,
    8.84 -    GST_PAD_SOMETIMES,
    8.85 -    GST_STATIC_CAPS_ANY);
    8.86 -
    8.87 -static GstStaticPadTemplate video_src_template =
    8.88 -GST_STATIC_PAD_TEMPLATE ("video_src",
    8.89 -    GST_PAD_SRC,
    8.90 -    GST_PAD_SOMETIMES,
    8.91 -    GST_STATIC_CAPS_ANY);
    8.92 -
    8.93 -/* NUV Demux indexes init/dispose callers */
    8.94 -static void gst_nuv_demux_index_init( nuv_demux_index **p_idx );
    8.95 -static void gst_nuv_demux_index_clean( nuv_demux_index **p_idx );
    8.96 -
    8.97 -/* NUV Demux indexes manipulation functions */
    8.98 -//static gint64 gst_nuv_demux_index_find_offset( GstNuvDemux *nuv, gint64 i_offset );
    8.99 -static void gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset );
   8.100 -static gint64 gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time );
   8.101 -
   8.102 -/* NUV Demux plug-in time-line functions */
   8.103 -static void gst_nuv_demux_finalize (GObject * object);
   8.104 -static GstStateChangeReturn gst_nuv_demux_change_state (GstElement * element,
   8.105 -    GstStateChange transition);
   8.106 -static void gst_nuv_demux_loop (GstPad * pad);
   8.107 -static GstFlowReturn gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf);
   8.108 -static GstFlowReturn gst_nuv_demux_play (GstPad * pad);
   8.109 -static gboolean gst_nuv_demux_sink_activate_pull (GstPad * sinkpad,
   8.110 -    gboolean active);
   8.111 -static gboolean gst_nuv_demux_sink_activate (GstPad * sinkpad);
   8.112 -static GstFlowReturn gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size,
   8.113 -    gboolean move, GstBuffer ** buffer);
   8.114 -static void gst_nuv_demux_reset (GstNuvDemux * nuv);
   8.115 -static gboolean gst_nuv_demux_handle_sink_event (GstPad * sinkpad,
   8.116 -    GstEvent * event);
   8.117 -static gboolean gst_nuv_demux_handle_audio_src_event (GstPad * sinkpad,
   8.118 -    GstEvent * event);
   8.119 -static gboolean gst_nuv_demux_handle_video_src_event (GstPad * sinkpad,
   8.120 -    GstEvent * event);
   8.121 -static void gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv);
   8.122 -static void gst_nuv_demux_send_eos (GstNuvDemux * nuv);
   8.123 -
   8.124 -/* GObject methods */
   8.125 -GST_BOILERPLATE (GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
   8.126 -
   8.127 -#if G_BYTE_ORDER == G_BIG_ENDIAN
   8.128 -static inline gdouble
   8.129 -_gdouble_swap_le_be (gdouble * d)
   8.130 -{
   8.131 -  union
   8.132 -  {
   8.133 -    guint64 i;
   8.134 -    gdouble d;
   8.135 -  } u;
   8.136 -
   8.137 -  u.d = *d;
   8.138 -  u.i = GUINT64_SWAP_LE_BE (u.i);
   8.139 -  return u.d;
   8.140 -}
   8.141 -
   8.142 -#define READ_DOUBLE_FROM_LE(d) (_gdouble_swap_le_be((gdouble* ) d))
   8.143 -#else /* G_BYTE_ORDER != G_BIG_ENDIAN */
   8.144 -#define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
   8.145 -#endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
   8.146 -
   8.147 -static void
   8.148 -gst_nuv_demux_base_init (gpointer klass)
   8.149 -{
   8.150 -  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   8.151 -
   8.152 -  gst_element_class_add_pad_template (element_class,
   8.153 -      gst_static_pad_template_get (&audio_src_template));
   8.154 -
   8.155 -  gst_element_class_add_pad_template (element_class,
   8.156 -      gst_static_pad_template_get (&video_src_template));
   8.157 -
   8.158 -  gst_element_class_add_pad_template (element_class,
   8.159 -      gst_static_pad_template_get (&sink_template));
   8.160 -  gst_element_class_set_details (element_class, &gst_nuv_demux_details);
   8.161 -}
   8.162 -
   8.163 -static void
   8.164 -gst_nuv_demux_class_init (GstNuvDemuxClass * klass)
   8.165 -{
   8.166 -  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
   8.167 -  GObjectClass *gobject_class = (GObjectClass *) klass;
   8.168 -
   8.169 -  GST_DEBUG_CATEGORY_INIT (nuvdemux_debug, "nuvdemux",
   8.170 -      0, "Demuxer for NUV streams");
   8.171 -
   8.172 -  parent_class = g_type_class_peek_parent (klass);
   8.173 -
   8.174 -  gobject_class->finalize = gst_nuv_demux_finalize;
   8.175 -  gstelement_class->change_state = gst_nuv_demux_change_state;
   8.176 -}
   8.177 -
   8.178 -static void
   8.179 -gst_nuv_demux_init (GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
   8.180 -{
   8.181 -  nuv->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
   8.182 -
   8.183 -  gst_pad_set_activate_function (nuv->sinkpad, gst_nuv_demux_sink_activate);
   8.184 -
   8.185 -  gst_pad_set_activatepull_function (nuv->sinkpad,
   8.186 -      gst_nuv_demux_sink_activate_pull);
   8.187 -
   8.188 -  gst_pad_set_chain_function (nuv->sinkpad,
   8.189 -      GST_DEBUG_FUNCPTR (gst_nuv_demux_chain));
   8.190 -
   8.191 -  gst_pad_set_event_function (nuv->sinkpad, gst_nuv_demux_handle_sink_event);
   8.192 -
   8.193 -  gst_element_add_pad (GST_ELEMENT (nuv), nuv->sinkpad);
   8.194 -  
   8.195 -  gst_nuv_demux_index_init( &nuv->index_entries );
   8.196 -
   8.197 -  nuv->adapter = NULL;
   8.198 -  nuv->mpeg_buffer = NULL;
   8.199 -  nuv->h = NULL;
   8.200 -  nuv->eh = NULL;
   8.201 -  nuv->fh = NULL;
   8.202 -  gst_nuv_demux_reset (nuv);
   8.203 -}
   8.204 -
   8.205 -static void
   8.206 -gst_nuv_demux_finalize (GObject * object)
   8.207 -{
   8.208 -  GstNuvDemux *nuv = GST_NUV_DEMUX (object);
   8.209 -
   8.210 -  if (nuv->mpeg_buffer != NULL) {
   8.211 -    gst_buffer_unref (nuv->mpeg_buffer);
   8.212 -  }
   8.213 -  
   8.214 -  if ( nuv->index_entries != NULL ) {
   8.215 -  	gst_nuv_demux_index_clean( &nuv->index_entries );
   8.216 -  	nuv->index_entries = NULL;
   8.217 -  }
   8.218 -
   8.219 -  gst_nuv_demux_destoy_src_pad (nuv);
   8.220 -  gst_nuv_demux_reset (nuv);
   8.221 -  if (nuv->adapter != NULL) {
   8.222 -    gst_object_unref (nuv->adapter);
   8.223 -  }
   8.224 -  G_OBJECT_CLASS (parent_class)->finalize (object);
   8.225 -}
   8.226 -
   8.227 -
   8.228 -/*****************************************************************************
   8.229 - * Indexes (timecode offset conversion) functions
   8.230 - *****************************************************************************/
   8.231 -
   8.232 -static void 
   8.233 -gst_nuv_demux_index_init( nuv_demux_index **p_idx )
   8.234 -{
   8.235 -	*p_idx = g_new0( nuv_demux_index, 1 );
   8.236 -	(*p_idx)->i_idx = 0;
   8.237 -	(*p_idx)->i_idx_max = 0;
   8.238 -}
   8.239 -
   8.240 -static void 
   8.241 -gst_nuv_demux_index_clean( nuv_demux_index **p_idx )
   8.242 -{
   8.243 -	if ( *p_idx != NULL ) {
   8.244 -		g_free( *p_idx );
   8.245 -		*p_idx = NULL;
   8.246 -	}
   8.247 -
   8.248 -}
   8.249 -
   8.250 -static void 
   8.251 -gst_nuv_demux_index_append( GstNuvDemux *nuv, gint64 i_time, gint64 i_offset )
   8.252 -{
   8.253 -	nuv_demux_index *p_idx = nuv->index_entries;
   8.254 -
   8.255 -	//if ( p_idx == NULL )
   8.256 -	//	return;
   8.257 -
   8.258 -	/* Be sure to append new entry (we don't insert point) */
   8.259 -	if( p_idx != NULL && p_idx->i_idx > 0 && p_idx->idx[p_idx->i_idx-1].i_time >= i_time )
   8.260 -		return;
   8.261 -
   8.262 -	/* */
   8.263 -	if( p_idx->i_idx >= p_idx->i_idx_max )
   8.264 -	{
   8.265 -		if( p_idx->i_idx >= DEMUX_INDEX_SIZE_MAX )
   8.266 -		{
   8.267 -			/* Avoid too big index */
   8.268 -			const gint64 i_length = p_idx->idx[p_idx->i_idx-1].i_time -
   8.269 -				p_idx->idx[0].i_time;
   8.270 -			const gint i_count = DEMUX_INDEX_SIZE_MAX/2;
   8.271 -			gint i, j;
   8.272 -
   8.273 -			/* We try to reduce the resolution of the index by a factor 2 */
   8.274 -			for( i = 1, j = 1; i < p_idx->i_idx; i++ )
   8.275 -			{
   8.276 -				if( p_idx->idx[i].i_time < j * i_length / i_count )
   8.277 -					continue;
   8.278 -
   8.279 -				p_idx->idx[j++] = p_idx->idx[i];
   8.280 -			}
   8.281 -			p_idx->i_idx = j;
   8.282 -
   8.283 -			if( p_idx->i_idx > 3 * DEMUX_INDEX_SIZE_MAX / 4 )
   8.284 -			{
   8.285 -				/* We haven't created enough space
   8.286 -				 * (This method won't create a good index but work for sure) */
   8.287 -				for( i = 0; i < p_idx->i_idx/2; i++ )
   8.288 -					p_idx->idx[i] = p_idx->idx[2*i];
   8.289 -				p_idx->i_idx /= 2;
   8.290 -			}
   8.291 -		}
   8.292 -		else
   8.293 -		{
   8.294 -			p_idx->i_idx_max += 1000;
   8.295 -		}
   8.296 -	}
   8.297 -
   8.298 -	/* */
   8.299 -	p_idx->idx[p_idx->i_idx].i_time = i_time;
   8.300 -	p_idx->idx[p_idx->i_idx].i_offset = i_offset;
   8.301 -
   8.302 -	p_idx->i_idx++;
   8.303 -}
   8.304 -
   8.305 -static gint64 
   8.306 -gst_nuv_demux_index_convert_time( GstNuvDemux *nuv, gint64 i_time )
   8.307 -{
   8.308 -	nuv_demux_index *p_idx = nuv->index_entries;
   8.309 -
   8.310 -	g_return_val_if_fail( p_idx != NULL , i_time );
   8.311 -
   8.312 -	gint i_min = 0;
   8.313 -	gint i_max = p_idx->i_idx-1;
   8.314 -
   8.315 -	/* Empty index */
   8.316 -	if( p_idx->i_idx <= 0 )
   8.317 -		return -1;
   8.318 -
   8.319 -	/* Special border case */
   8.320 -	if( i_time <= p_idx->idx[0].i_time )
   8.321 -		return p_idx->idx[0].i_offset;
   8.322 -	if( i_time >= p_idx->idx[i_max].i_time )
   8.323 -		return p_idx->idx[i_max].i_offset;
   8.324 -
   8.325 -	/* Dicho */
   8.326 -	for( ;; )
   8.327 -	{
   8.328 -		gint i_med;
   8.329 -
   8.330 -		if( i_max - i_min <= 1 )
   8.331 -			break;
   8.332 -
   8.333 -		i_med = (i_min+i_max)/2;
   8.334 -		if( p_idx->idx[i_med].i_time < i_time )
   8.335 -			i_min = i_med;
   8.336 -		else if( p_idx->idx[i_med].i_time > i_time )
   8.337 -			i_max = i_med;
   8.338 -		else
   8.339 -			return p_idx->idx[i_med].i_offset;
   8.340 -	}
   8.341 -
   8.342 -	/* return nearest in time */
   8.343 -	if( i_time - p_idx->idx[i_min].i_time < p_idx->idx[i_max].i_time - i_time )
   8.344 -		return p_idx->idx[i_min].i_offset;
   8.345 -	else
   8.346 -		return p_idx->idx[i_max].i_offset;
   8.347 -}
   8.348 -
   8.349 -/*****************************************************************************
   8.350 - * Utils functions
   8.351 - *****************************************************************************/
   8.352 -
   8.353 -static gboolean
   8.354 -gst_nuv_demux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
   8.355 -{
   8.356 -  gboolean res = FALSE;
   8.357 -
   8.358 -  switch (GST_EVENT_TYPE (event)) {
   8.359 -    case GST_EVENT_NEWSEGMENT:
   8.360 -      res = TRUE;
   8.361 -      break;
   8.362 -    default:
   8.363 -      return gst_pad_event_default (sinkpad, event);
   8.364 -      break;
   8.365 -  }
   8.366 -
   8.367 -  gst_event_unref (event);
   8.368 -  return res;
   8.369 -}
   8.370 -
   8.371 -/* HeaderLoad:
   8.372 - */
   8.373 -static GstFlowReturn
   8.374 -gst_nuv_demux_header_load (GstNuvDemux * nuv, nuv_header ** h_ret)
   8.375 -{
   8.376 -  GstBuffer *buffer = NULL;
   8.377 -  GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 72, TRUE, &buffer);
   8.378 -
   8.379 -  if (res != GST_FLOW_OK)
   8.380 -    return res;
   8.381 -
   8.382 -  nuv_header *h = g_new0 (nuv_header, 1);
   8.383 -
   8.384 -  memcpy (h->id, buffer->data, 12);
   8.385 -  memcpy (h->version, buffer->data + 12, 5);
   8.386 -  h->i_width = GST_READ_UINT32_LE (&buffer->data[20]);
   8.387 -  h->i_height = GST_READ_UINT32_LE (&buffer->data[24]);
   8.388 -  h->i_width_desired = GST_READ_UINT32_LE (&buffer->data[28]);
   8.389 -  h->i_height_desired = GST_READ_UINT32_LE (&buffer->data[32]);
   8.390 -  h->i_mode = buffer->data[36];
   8.391 -  h->d_aspect = READ_DOUBLE_FROM_LE (&buffer->data[40]);
   8.392 -  h->d_fps = READ_DOUBLE_FROM_LE (&buffer->data[48]);
   8.393 -  h->i_video_blocks = GST_READ_UINT32_LE (&buffer->data[56]);
   8.394 -  h->i_audio_blocks = GST_READ_UINT32_LE (&buffer->data[60]);
   8.395 -  h->i_text_blocks = GST_READ_UINT32_LE (&buffer->data[64]);
   8.396 -  h->i_keyframe_distance = GST_READ_UINT32_LE (&buffer->data[68]);
   8.397 -
   8.398 -  GST_DEBUG_OBJECT (nuv,
   8.399 -      "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d", h->id,
   8.400 -      h->version, h->i_width, h->i_height, h->d_aspect, h->d_fps,
   8.401 -      h->i_video_blocks, h->i_audio_blocks, h->i_text_blocks,
   8.402 -      h->i_keyframe_distance);
   8.403 -
   8.404 -  *h_ret = h;
   8.405 -  gst_buffer_unref (buffer);
   8.406 -  return res;
   8.407 -}
   8.408 -
   8.409 -static GstFlowReturn
   8.410 -gst_nuv_demux_stream_header_data (GstNuvDemux * nuv)
   8.411 -{
   8.412 -  GstFlowReturn res = gst_nuv_demux_header_load (nuv, &nuv->h);
   8.413 -
   8.414 -  if (res == GST_FLOW_OK)
   8.415 -    nuv->state = GST_NUV_DEMUX_EXTRA_DATA;
   8.416 -  return res;
   8.417 -}
   8.418 -
   8.419 -/*
   8.420 - * Read NUV file tag
   8.421 - */
   8.422 -static GstFlowReturn
   8.423 -gst_nuv_demux_stream_file_header (GstNuvDemux * nuv)
   8.424 -{
   8.425 -  GstFlowReturn res = GST_FLOW_OK;
   8.426 -  GstBuffer *file_header = NULL;
   8.427 -
   8.428 -  res = gst_nuv_demux_read_bytes (nuv, 12, FALSE, &file_header);
   8.429 -  if (res != GST_FLOW_OK) {
   8.430 -    return res;
   8.431 -  } else {
   8.432 -    if (strncmp ((gchar *) file_header->data, "MythTVVideo", 11) ||
   8.433 -        strncmp ((gchar *) file_header->data, "NuppelVideo", 11)) {
   8.434 -      nuv->state = GST_NUV_DEMUX_HEADER_DATA;
   8.435 -    } else {
   8.436 -      GST_DEBUG_OBJECT (nuv, "error parsing file header");
   8.437 -      nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   8.438 -      res = GST_FLOW_ERROR;
   8.439 -    }
   8.440 -  }
   8.441 -  if (file_header != NULL) {
   8.442 -    gst_buffer_unref (file_header);
   8.443 -  }
   8.444 -  return res;
   8.445 -}
   8.446 -
   8.447 -/* FrameHeaderLoad:
   8.448 - */
   8.449 -static GstFlowReturn
   8.450 -gst_nuv_demux_frame_header_load (GstNuvDemux * nuv, nuv_frame_header ** h_ret)
   8.451 -{
   8.452 -  unsigned char *data;
   8.453 -  nuv_frame_header *h;
   8.454 -  GstBuffer *buf = NULL;
   8.455 -
   8.456 -  GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 12, TRUE, &buf);
   8.457 -
   8.458 -  if (res != GST_FLOW_OK) {
   8.459 -    if (buf != NULL) {
   8.460 -      gst_buffer_unref (buf);
   8.461 -    }
   8.462 -    return res;
   8.463 -  }
   8.464 -
   8.465 -  h = g_new0 (nuv_frame_header, 1);
   8.466 -  data = buf->data;
   8.467 -
   8.468 -  h->i_type = data[0];
   8.469 -  h->i_compression = data[1];
   8.470 -  h->i_keyframe = data[2];
   8.471 -  h->i_filters = data[3];
   8.472 -
   8.473 -  h->i_timecode = GST_READ_UINT32_LE (&data[4]);
   8.474 -
   8.475 -
   8.476 -  h->i_length = GST_READ_UINT32_LE (&data[8]);
   8.477 -  GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
   8.478 -      h->i_type,
   8.479 -      h->i_compression ? h->i_compression : ' ',
   8.480 -      h->i_keyframe ? h->i_keyframe : ' ',
   8.481 -      h->i_filters, h->i_timecode, h->i_length);
   8.482 -
   8.483 -  *h_ret = h;
   8.484 -  gst_buffer_unref (buf);
   8.485 -  return GST_FLOW_OK;
   8.486 -}
   8.487 -
   8.488 -static GstFlowReturn
   8.489 -gst_nuv_demux_extended_header_load (GstNuvDemux * nuv,
   8.490 -    nuv_extended_header ** h_ret)
   8.491 -{
   8.492 -  unsigned char *data;
   8.493 -  GstBuffer *buff = NULL;
   8.494 -  nuv_extended_header *h;
   8.495 -
   8.496 -
   8.497 -  GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 512, TRUE, &buff);
   8.498 -
   8.499 -  if (res != GST_FLOW_OK) {
   8.500 -    if (buff != NULL) {
   8.501 -      gst_buffer_unref (buff);
   8.502 -    }
   8.503 -    return res;
   8.504 -  }
   8.505 -
   8.506 -  h = g_new0 (nuv_extended_header, 1);
   8.507 -  data = buff->data;
   8.508 -  h->i_version = GST_READ_UINT32_LE (&data[0]);
   8.509 -  h->i_video_fcc = GST_MAKE_FOURCC (data[4], data[5], data[6], data[7]);
   8.510 -  h->i_audio_fcc = GST_MAKE_FOURCC (data[8], data[9], data[10], data[11]);
   8.511 -  h->i_audio_sample_rate = GST_READ_UINT32_LE (&data[12]);
   8.512 -  h->i_audio_bits_per_sample = GST_READ_UINT32_LE (&data[16]);
   8.513 -  h->i_audio_channels = GST_READ_UINT32_LE (&data[20]);
   8.514 -  h->i_audio_compression_ratio = GST_READ_UINT32_LE (&data[24]);
   8.515 -  h->i_audio_quality = GST_READ_UINT32_LE (&data[28]);
   8.516 -  h->i_rtjpeg_quality = GST_READ_UINT32_LE (&data[32]);
   8.517 -  h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE (&data[36]);
   8.518 -  h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE (&data[40]);
   8.519 -  h->i_lavc_bitrate = GST_READ_UINT32_LE (&data[44]);
   8.520 -  h->i_lavc_qmin = GST_READ_UINT32_LE (&data[48]);
   8.521 -  h->i_lavc_qmin = GST_READ_UINT32_LE (&data[52]);
   8.522 -  h->i_lavc_maxqdiff = GST_READ_UINT32_LE (&data[56]);
   8.523 -  h->i_seekable_offset = GST_READ_UINT64_LE (&data[60]);
   8.524 -  h->i_keyframe_adjust_offset = GST_READ_UINT64_LE (&data[68]);
   8.525 -
   8.526 -  GST_DEBUG_OBJECT (nuv,
   8.527 -      "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d"
   8.528 -      "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld",
   8.529 -      h->i_version, (gchar *) & h->i_video_fcc, (gchar *) & h->i_audio_fcc,
   8.530 -      h->i_audio_sample_rate, h->i_audio_bits_per_sample, h->i_audio_channels,
   8.531 -      h->i_audio_compression_ratio, h->i_audio_quality, h->i_rtjpeg_quality,
   8.532 -      h->i_rtjpeg_luma_filter, h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate,
   8.533 -      h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff, h->i_seekable_offset,
   8.534 -      h->i_keyframe_adjust_offset);
   8.535 -
   8.536 -  *h_ret = h;
   8.537 -  gst_buffer_unref (buff);
   8.538 -  return res;
   8.539 -}
   8.540 -
   8.541 -static gboolean
   8.542 -gst_nuv_demux_handle_audio_src_event (GstPad * pad, GstEvent * event)
   8.543 -{
   8.544 -  gst_event_unref (event);
   8.545 -  return FALSE;
   8.546 -}
   8.547 -
   8.548 -static gboolean
   8.549 -gst_nuv_demux_handle_video_src_event (GstPad * pad, GstEvent * event)
   8.550 -{
   8.551 -  gst_event_unref (event);
   8.552 -  return FALSE;
   8.553 -}
   8.554 -
   8.555 -static void
   8.556 -gst_nuv_demux_create_pads (GstNuvDemux * nuv)
   8.557 -{
   8.558 -  if (nuv->h->i_video_blocks != 0) {
   8.559 -    GstCaps *video_caps = NULL;
   8.560 -
   8.561 -    nuv->src_video_pad =
   8.562 -        gst_pad_new_from_static_template (&video_src_template, "video_src");
   8.563 -
   8.564 -    video_caps = gst_caps_new_simple ("video/x-divx",
   8.565 -        "divxversion", G_TYPE_INT, 4,
   8.566 -        "width", G_TYPE_INT, nuv->h->i_width,
   8.567 -        "height", G_TYPE_INT, nuv->h->i_height,
   8.568 -        "framerate", GST_TYPE_FRACTION, (gint) (nuv->h->d_fps * 1000.0f), 1000,
   8.569 -        "pixel-aspect-ratio", GST_TYPE_FRACTION,
   8.570 -        (gint) (nuv->h->d_aspect * 1000.0f), 1000, NULL);
   8.571 -
   8.572 -    gst_pad_use_fixed_caps (nuv->src_video_pad);
   8.573 -    gst_pad_set_caps (nuv->src_video_pad, video_caps);
   8.574 -
   8.575 -    gst_pad_set_event_function (nuv->src_video_pad,
   8.576 -	    	gst_nuv_demux_handle_video_src_event);
   8.577 -    gst_pad_set_active (nuv->src_video_pad, TRUE);
   8.578 -    gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
   8.579 -
   8.580 -    gst_caps_unref (video_caps);
   8.581 -  }
   8.582 -
   8.583 -  if (nuv->h->i_audio_blocks != 0) {
   8.584 -    GstCaps *audio_caps = NULL;
   8.585 -
   8.586 -    nuv->src_audio_pad =
   8.587 -        gst_pad_new_from_static_template (&audio_src_template, "audio_src");
   8.588 -
   8.589 -    audio_caps = gst_caps_new_simple ("audio/mpeg",
   8.590 -        "rate", G_TYPE_INT, nuv->eh->i_audio_sample_rate,
   8.591 -        "format", GST_TYPE_FOURCC, nuv->eh->i_audio_fcc,
   8.592 -        "channels", G_TYPE_INT, nuv->eh->i_audio_channels,
   8.593 -        "mpegversion", G_TYPE_INT, nuv->eh->i_version, NULL);
   8.594 -
   8.595 -    gst_pad_use_fixed_caps (nuv->src_audio_pad);
   8.596 -    gst_pad_set_caps (nuv->src_audio_pad, audio_caps);
   8.597 -    
   8.598 -    gst_pad_set_event_function (nuv->src_audio_pad,
   8.599 -  		  gst_nuv_demux_handle_audio_src_event);
   8.600 -    gst_pad_set_active (nuv->src_audio_pad, TRUE);
   8.601 -    gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
   8.602 -
   8.603 -    gst_caps_unref (audio_caps);
   8.604 -  }
   8.605 -
   8.606 -  gst_element_no_more_pads (GST_ELEMENT (nuv));
   8.607 -}
   8.608 -
   8.609 -static GstFlowReturn
   8.610 -gst_nuv_demux_read_head_frame (GstNuvDemux * nuv)
   8.611 -{
   8.612 -  GstFlowReturn ret = GST_FLOW_OK;
   8.613 -
   8.614 -  ret = gst_nuv_demux_frame_header_load (nuv, &nuv->fh);
   8.615 -  if (ret != GST_FLOW_OK)
   8.616 -    return ret;
   8.617 -
   8.618 -  nuv->state = GST_NUV_DEMUX_MOVI;
   8.619 -  return ret;
   8.620 -}
   8.621 -
   8.622 -static GstFlowReturn
   8.623 -gst_nuv_demux_stream_data (GstNuvDemux * nuv)
   8.624 -{
   8.625 -  GstFlowReturn ret = GST_FLOW_OK;
   8.626 -  GstBuffer *buf = NULL;
   8.627 -  nuv_frame_header *h = nuv->fh;
   8.628 -  
   8.629 -  gint64 table_timecode = 0;
   8.630 -
   8.631 -  if (h->i_type == 'R')
   8.632 -    goto done;
   8.633 -    
   8.634 -  table_timecode = h->i_timecode;
   8.635 -
   8.636 -  /* append the frame's header timecode field, and the actual offset */
   8.637 -  if ( h->i_type == 'V' ) 
   8.638 -  	gst_nuv_demux_index_append( nuv, h->i_timecode, nuv->video_offset );
   8.639 -  else if ( h->i_type == 'A' ) 
   8.640 -  	gst_nuv_demux_index_append( nuv, h->i_timecode, nuv->audio_offset );  	
   8.641 - 
   8.642 -  if (h->i_length > 0) {
   8.643 -	  ret = gst_nuv_demux_read_bytes (nuv, h->i_length, TRUE, &buf);
   8.644 -	  if (ret != GST_FLOW_OK)
   8.645 -		  return ret;
   8.646 -
   8.647 -	  /* search for a valid timecode in the indexes list (find the nearest valid timecode) */
   8.648 -	  if ( h->i_timecode < 0 ) {
   8.649 -		  /* convert this actual timecode to a valid index in the timecode's table */
   8.650 -		  gint64 pos = gst_nuv_demux_index_convert_time( nuv, h->i_timecode );
   8.651 -
   8.652 -		  /* just get the timecode from the timecode's table */		  
   8.653 -		  table_timecode = nuv->index_entries->idx[pos].i_time * GST_MSECOND;
   8.654 -	  } else {  
   8.655 -			table_timecode = h->i_timecode * GST_MSECOND;
   8.656 -	  }
   8.657 -	  
   8.658 -	  GST_BUFFER_TIMESTAMP (buf) = table_timecode;
   8.659 -  }  
   8.660 -
   8.661 -  switch (h->i_type) {
   8.662 -    case 'V':
   8.663 -    {
   8.664 -      if (h->i_length == 0)
   8.665 -        break;
   8.666 -        
   8.667 -      if ( !gst_pad_is_linked( nuv->src_video_pad ) )
   8.668 -      	break;
   8.669 -      
   8.670 -      //GST_PAD_STREAM_LOCK(nuv->src_video_pad);
   8.671 -      
   8.672 -      GST_BUFFER_SIZE (buf) = h->i_length;
   8.673 -      gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_video_pad));
   8.674 -      ret = gst_pad_push (nuv->src_video_pad, buf);
   8.675 -      nuv->video_offset += h->i_length;
   8.676 -      
   8.677 -      //GST_PAD_STREAM_UNLOCK(nuv->src_video_pad);
   8.678 -      break;
   8.679 -    }
   8.680 -    case 'A':
   8.681 -    {
   8.682 -      if (h->i_length == 0)
   8.683 -        break;
   8.684 -        
   8.685 -      if ( !gst_pad_is_linked( nuv->src_audio_pad ) )
   8.686 -      	break;
   8.687 -        
   8.688 -      //GST_PAD_STREAM_LOCK(nuv->src_audio_pad);
   8.689 -      
   8.690 -      GST_BUFFER_SIZE (buf) = h->i_length;
   8.691 -      gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_audio_pad));
   8.692 -      ret = gst_pad_push (nuv->src_audio_pad, buf);
   8.693 -      nuv->audio_offset += h->i_length;
   8.694 -      
   8.695 -      //GST_PAD_STREAM_UNLOCK(nuv->src_audio_pad);
   8.696 -      break;
   8.697 -    }
   8.698 -    case 'S':
   8.699 -    {
   8.700 -      switch (h->i_compression) {
   8.701 -        case 'V':
   8.702 -		      if ( !gst_pad_is_linked( nuv->src_video_pad ) )
   8.703 -		      	break;
   8.704 -
   8.705 -        	//GST_PAD_STREAM_LOCK(nuv->src_video_pad);
   8.706 -          gst_pad_push_event (nuv->src_video_pad,
   8.707 -              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, table_timecode, 
   8.708 -              		GST_CLOCK_TIME_NONE, 0));
   8.709 -          //GST_PAD_STREAM_UNLOCK(nuv->src_video_pad);
   8.710 -          break;
   8.711 -        case 'A':        
   8.712 -		      if ( !gst_pad_is_linked( nuv->src_audio_pad ) )
   8.713 -		      	break;
   8.714 -
   8.715 -        	//GST_PAD_STREAM_LOCK(nuv->src_audio_pad);
   8.716 -          gst_pad_push_event (nuv->src_audio_pad,
   8.717 -              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, table_timecode, 
   8.718 -              		GST_CLOCK_TIME_NONE, 0));
   8.719 -          //GST_PAD_STREAM_UNLOCK(nuv->src_audio_pad);
   8.720 -          break;
   8.721 -        default:
   8.722 -          break;
   8.723 -      }
   8.724 -    }
   8.725 -    default:
   8.726 -      if (buf != NULL)
   8.727 -        gst_buffer_unref (buf);
   8.728 -
   8.729 -      break;
   8.730 -  }
   8.731 -
   8.732 -done:
   8.733 -  nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   8.734 -  g_free (nuv->fh);
   8.735 -  nuv->fh = NULL;
   8.736 -  return ret;
   8.737 -}
   8.738 -
   8.739 -static GstFlowReturn
   8.740 -gst_nuv_demux_stream_mpeg_data (GstNuvDemux * nuv)
   8.741 -{
   8.742 -  GstFlowReturn ret = GST_FLOW_OK;
   8.743 -
   8.744 -  /* ffmpeg extra data */
   8.745 -  ret =
   8.746 -      gst_nuv_demux_read_bytes (nuv, nuv->mpeg_data_size, TRUE,
   8.747 -      &nuv->mpeg_buffer);
   8.748 -  if (ret != GST_FLOW_OK) {
   8.749 -    return ret; //GST_FLOW_ERROR;
   8.750 -  }
   8.751 -  GST_BUFFER_SIZE (nuv->mpeg_buffer) = nuv->mpeg_data_size;
   8.752 -  nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   8.753 -  return ret;
   8.754 -}
   8.755 -
   8.756 -static GstFlowReturn
   8.757 -gst_nuv_demux_stream_extra_data (GstNuvDemux * nuv)
   8.758 -{
   8.759 -  GstFlowReturn ret = GST_FLOW_OK;
   8.760 -
   8.761 -  /* Load 'D' */
   8.762 -  nuv_frame_header *h;
   8.763 -
   8.764 -  ret = gst_nuv_demux_frame_header_load (nuv, &h);
   8.765 -  if (ret != GST_FLOW_OK)
   8.766 -    return ret;
   8.767 -
   8.768 -  if (h->i_type != 'D') {
   8.769 -    g_free (h);
   8.770 -    return GST_FLOW_ERROR;
   8.771 -  }
   8.772 -
   8.773 -  if (h->i_length > 0) {
   8.774 -    if (h->i_compression == 'F') {
   8.775 -      nuv->state = GST_NUV_DEMUX_MPEG_DATA;
   8.776 -    } else {
   8.777 -      g_free (h);
   8.778 -      return GST_FLOW_ERROR;
   8.779 -    }
   8.780 -  } else {
   8.781 -    nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   8.782 -  }
   8.783 -
   8.784 -  g_free (h);
   8.785 -  h = NULL;
   8.786 -  return ret;
   8.787 -}
   8.788 -
   8.789 -static GstFlowReturn
   8.790 -gst_nuv_demux_stream_extend_header_data (GstNuvDemux * nuv)
   8.791 -{
   8.792 -  GstFlowReturn ret = GST_FLOW_OK;
   8.793 -
   8.794 -  ret = gst_nuv_demux_extended_header_load (nuv, &nuv->eh);
   8.795 -  if (ret != GST_FLOW_OK)
   8.796 -    return ret;
   8.797 -
   8.798 -  gst_nuv_demux_create_pads (nuv);
   8.799 -  nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   8.800 -  return ret;
   8.801 -}
   8.802 -
   8.803 -static GstFlowReturn
   8.804 -gst_nuv_demux_stream_extend_header (GstNuvDemux * nuv)
   8.805 -{
   8.806 -  GstBuffer *buf = NULL;
   8.807 -  GstFlowReturn res = GST_FLOW_OK;
   8.808 -
   8.809 -  res = gst_nuv_demux_read_bytes (nuv, 1, FALSE, &buf);
   8.810 -  if (res != GST_FLOW_OK) {
   8.811 -    if (buf != NULL) {
   8.812 -      gst_buffer_unref (buf);
   8.813 -    }
   8.814 -    return res;
   8.815 -  }
   8.816 -
   8.817 -  if (buf->data[0] == 'X') {
   8.818 -    gst_buffer_unref (buf);
   8.819 -    buf = NULL;
   8.820 -    nuv_frame_header *h = NULL;
   8.821 -
   8.822 -    res = gst_nuv_demux_frame_header_load (nuv, &h);
   8.823 -    if (res != GST_FLOW_OK)
   8.824 -      return res;
   8.825 -
   8.826 -    if (h->i_length != 512) {
   8.827 -      g_free (h);
   8.828 -      return GST_FLOW_ERROR;
   8.829 -    }
   8.830 -    g_free (h);
   8.831 -    h = NULL;
   8.832 -    nuv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
   8.833 -  } else {
   8.834 -    nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   8.835 -    g_object_unref (buf);
   8.836 -    GST_ELEMENT_WARNING (nuv, STREAM, FAILED,
   8.837 -        (_("incomplete NUV support")), ("incomplete NUV support"));
   8.838 -    return GST_FLOW_ERROR;
   8.839 -  }
   8.840 -  return res;
   8.841 -}
   8.842 -
   8.843 -static GstFlowReturn
   8.844 -gst_nuv_demux_play (GstPad * pad)
   8.845 -{
   8.846 -  GstFlowReturn res = GST_FLOW_OK;
   8.847 -  GstNuvDemux *nuv = GST_NUV_DEMUX (GST_PAD_PARENT (pad));
   8.848 -
   8.849 -  switch (nuv->state) {
   8.850 -    case GST_NUV_DEMUX_START:
   8.851 -      res = gst_nuv_demux_stream_file_header (nuv);
   8.852 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   8.853 -        goto pause;
   8.854 -      }
   8.855 -      if (nuv->state != GST_NUV_DEMUX_HEADER_DATA)
   8.856 -        break;
   8.857 -
   8.858 -    case GST_NUV_DEMUX_HEADER_DATA:
   8.859 -      res = gst_nuv_demux_stream_header_data (nuv);
   8.860 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   8.861 -        goto pause;
   8.862 -      }
   8.863 -      if (nuv->state != GST_NUV_DEMUX_EXTRA_DATA)
   8.864 -        break;
   8.865 -
   8.866 -    case GST_NUV_DEMUX_EXTRA_DATA:
   8.867 -      res = gst_nuv_demux_stream_extra_data (nuv);
   8.868 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   8.869 -        goto pause;
   8.870 -      }
   8.871 -      if (nuv->state != GST_NUV_DEMUX_MPEG_DATA)
   8.872 -        break;
   8.873 -
   8.874 -    case GST_NUV_DEMUX_MPEG_DATA:
   8.875 -      res = gst_nuv_demux_stream_mpeg_data (nuv);
   8.876 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   8.877 -        goto pause;
   8.878 -      }
   8.879 -
   8.880 -      if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER)
   8.881 -        break;
   8.882 -
   8.883 -    case GST_NUV_DEMUX_EXTEND_HEADER:
   8.884 -      res = gst_nuv_demux_stream_extend_header (nuv);
   8.885 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   8.886 -        goto pause;
   8.887 -      }
   8.888 -      if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER_DATA)
   8.889 -        break;
   8.890 -
   8.891 -    case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
   8.892 -      res = gst_nuv_demux_stream_extend_header_data (nuv);
   8.893 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   8.894 -        goto pause;
   8.895 -      }
   8.896 -
   8.897 -      if (nuv->state != GST_NUV_DEMUX_FRAME_HEADER)
   8.898 -        break;
   8.899 -
   8.900 -    case GST_NUV_DEMUX_FRAME_HEADER:
   8.901 -      res = gst_nuv_demux_read_head_frame (nuv);
   8.902 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   8.903 -        goto pause;
   8.904 -      }
   8.905 -      if (nuv->state != GST_NUV_DEMUX_MOVI)
   8.906 -        break;
   8.907 -
   8.908 -    case GST_NUV_DEMUX_MOVI:
   8.909 -      res = gst_nuv_demux_stream_data (nuv);
   8.910 -      if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA) && (res != GST_FLOW_CUSTOM_ERROR)) {
   8.911 -        goto pause;
   8.912 -      }
   8.913 -      break;
   8.914 -    case GST_NUV_DEMUX_INVALID_DATA:
   8.915 -      goto pause;
   8.916 -      break;
   8.917 -    default:
   8.918 -      g_assert_not_reached ();
   8.919 -  }
   8.920 -
   8.921 -  GST_DEBUG_OBJECT (nuv, "state: %d res:%s", nuv->state,
   8.922 -      gst_flow_get_name (res));
   8.923 -
   8.924 -  return GST_FLOW_OK;
   8.925 -
   8.926 -pause:
   8.927 -  GST_LOG_OBJECT (nuv, "pausing task, reason %s", gst_flow_get_name (res));
   8.928 -  gst_pad_pause_task (nuv->sinkpad);
   8.929 -  if (GST_FLOW_IS_FATAL (res)) {
   8.930 -    GST_ELEMENT_ERROR (nuv, STREAM, FAILED,
   8.931 -        (_("Internal data stream error.")),
   8.932 -        ("streaming stopped, reason %s", gst_flow_get_name (res)));
   8.933 -
   8.934 -    gst_nuv_demux_send_eos (nuv);
   8.935 -  }
   8.936 -  return res;
   8.937 -}
   8.938 -
   8.939 -static void
   8.940 -gst_nuv_demux_send_eos (GstNuvDemux * nuv)
   8.941 -{
   8.942 -  gst_element_post_message (GST_ELEMENT (nuv),
   8.943 -      gst_message_new_segment_done (GST_OBJECT (nuv), GST_FORMAT_TIME, -1));
   8.944 -
   8.945 -  if (nuv->src_video_pad)
   8.946 -    gst_pad_push_event (nuv->src_video_pad, gst_event_new_eos ());
   8.947 -  if (nuv->src_audio_pad)
   8.948 -    gst_pad_push_event (nuv->src_audio_pad, gst_event_new_eos ());
   8.949 -}
   8.950 -
   8.951 -static GstFlowReturn
   8.952 -gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size, gboolean move,
   8.953 -    GstBuffer ** buffer)
   8.954 -{
   8.955 -  GstFlowReturn ret = GST_FLOW_OK;
   8.956 -
   8.957 -  if (size == 0) {
   8.958 -    *buffer = gst_buffer_new ();
   8.959 -    return ret;
   8.960 -  }
   8.961 -  
   8.962 -  if (nuv->mode == 0) {
   8.963 -    ret = gst_pad_pull_range (nuv->sinkpad, nuv->offset, size, buffer);
   8.964 -    if (ret == GST_FLOW_OK) {
   8.965 -    		if (move) {
   8.966 -					nuv->offset += size;
   8.967 -				}    	
   8.968 -      /* got eos */
   8.969 -    } else if (ret == GST_FLOW_UNEXPECTED) {
   8.970 -      gst_nuv_demux_send_eos (nuv);
   8.971 -      return GST_FLOW_WRONG_STATE;
   8.972 -    }
   8.973 -  } else {
   8.974 -    if (gst_adapter_available (nuv->adapter) < size)
   8.975 -      return GST_FLOW_ERROR_NO_DATA;
   8.976 -
   8.977 -    if (move) {
   8.978 -      *buffer = gst_adapter_take_buffer (nuv->adapter, size);
   8.979 -    } else {
   8.980 -      guint8 *data = NULL;
   8.981 -
   8.982 -      data = (guint8 *) gst_adapter_peek (nuv->adapter, size);
   8.983 -      *buffer = gst_buffer_new ();
   8.984 -      gst_buffer_set_data (*buffer, data, size);
   8.985 -    }
   8.986 -  }
   8.987 -  
   8.988 -	
   8.989 -  return ret;
   8.990 -}
   8.991 -
   8.992 -static gboolean
   8.993 -gst_nuv_demux_sink_activate (GstPad * sinkpad)
   8.994 -{
   8.995 -  gboolean res = TRUE;
   8.996 -  GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
   8.997 -
   8.998 -  if (gst_pad_check_pull_range (sinkpad)) {
   8.999 -    nuv->mode = 0;
  8.1000 -    if (nuv->adapter) {
  8.1001 -      gst_adapter_clear (nuv->adapter);
  8.1002 -      g_object_unref (nuv->adapter);
  8.1003 -      nuv->adapter = NULL;
  8.1004 -    }
  8.1005 -    res = gst_pad_activate_pull (sinkpad, TRUE);
  8.1006 -  } else {
  8.1007 -    nuv->mode = 1;
  8.1008 -    if (nuv->adapter) {
  8.1009 -      gst_adapter_clear (nuv->adapter);
  8.1010 -    } else {
  8.1011 -      nuv->adapter = gst_adapter_new ();
  8.1012 -    }
  8.1013 -    res = gst_pad_activate_push (sinkpad, TRUE);
  8.1014 -  }
  8.1015 -
  8.1016 -  g_object_unref (nuv);
  8.1017 -  return res;
  8.1018 -}
  8.1019 -
  8.1020 -static gboolean
  8.1021 -gst_nuv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
  8.1022 -{
  8.1023 -  GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
  8.1024 -
  8.1025 -  if (active) {
  8.1026 -    gst_pad_start_task (sinkpad, (GstTaskFunction) gst_nuv_demux_loop, sinkpad);
  8.1027 -  } else {
  8.1028 -    gst_pad_stop_task (sinkpad);
  8.1029 -  }
  8.1030 -  gst_object_unref (nuv);
  8.1031 -
  8.1032 -  return TRUE;
  8.1033 -}
  8.1034 -
  8.1035 -static GstFlowReturn
  8.1036 -gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf)
  8.1037 -{
  8.1038 -  GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
  8.1039 -
  8.1040 -  gst_adapter_push (nuv->adapter, buf);
  8.1041 -
  8.1042 -  return gst_nuv_demux_play (pad);
  8.1043 -}
  8.1044 -
  8.1045 -static void
  8.1046 -gst_nuv_demux_loop (GstPad * pad)
  8.1047 -{
  8.1048 -  gst_nuv_demux_play (pad);
  8.1049 -}
  8.1050 -
  8.1051 -static void
  8.1052 -gst_nuv_demux_reset (GstNuvDemux * nuv)
  8.1053 -{
  8.1054 -  nuv->state = GST_NUV_DEMUX_START;
  8.1055 -  nuv->mode = 0;
  8.1056 -  nuv->offset = 0;
  8.1057 -  nuv->video_offset = 0;
  8.1058 -  nuv->audio_offset = 0;
  8.1059 -
  8.1060 -  if (nuv->adapter != NULL)
  8.1061 -    gst_adapter_clear (nuv->adapter);
  8.1062 -
  8.1063 -  if (nuv->mpeg_buffer != NULL) {
  8.1064 -    gst_buffer_unref (nuv->mpeg_buffer);
  8.1065 -    nuv->mpeg_buffer = NULL;
  8.1066 -  }
  8.1067 -
  8.1068 -  g_free (nuv->h);
  8.1069 -  nuv->h = NULL;
  8.1070 -
  8.1071 -  g_free (nuv->eh);
  8.1072 -  nuv->eh = NULL;
  8.1073 -
  8.1074 -  g_free (nuv->fh);
  8.1075 -  nuv->fh = NULL;
  8.1076 -}
  8.1077 -
  8.1078 -static void
  8.1079 -gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv)
  8.1080 -{
  8.1081 -  if (nuv->src_video_pad) {
  8.1082 -    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
  8.1083 -    nuv->src_video_pad = NULL;
  8.1084 -  }
  8.1085 -
  8.1086 -  if (nuv->src_audio_pad) {
  8.1087 -    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
  8.1088 -    nuv->src_audio_pad = NULL;
  8.1089 -  }
  8.1090 -}
  8.1091 -
  8.1092 -static GstStateChangeReturn
  8.1093 -gst_nuv_demux_change_state (GstElement * element, GstStateChange transition)
  8.1094 -{
  8.1095 -  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  8.1096 -
  8.1097 -  switch (transition) {
  8.1098 -    case GST_STATE_CHANGE_READY_TO_PAUSED:
  8.1099 -      break;
  8.1100 -    default:
  8.1101 -      break;
  8.1102 -  }
  8.1103 -
  8.1104 -  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  8.1105 -  if (ret == GST_STATE_CHANGE_FAILURE)
  8.1106 -    goto done;
  8.1107 -
  8.1108 -  switch (transition) {
  8.1109 -    case GST_STATE_CHANGE_PAUSED_TO_READY:
  8.1110 -      gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (element));
  8.1111 -      gst_nuv_demux_reset (GST_NUV_DEMUX (element));
  8.1112 -      break;
  8.1113 -    default:
  8.1114 -      break;
  8.1115 -  }
  8.1116 -
  8.1117 -done:
  8.1118 -  return ret;
  8.1119 -}
  8.1120 -
  8.1121 -static gboolean
  8.1122 -plugin_init (GstPlugin * plugin)
  8.1123 -{
  8.1124 -#ifdef ENABLE_NLS
  8.1125 -  setlocale (LC_ALL, "");
  8.1126 -  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  8.1127 -#endif /* ENABLE_NLS */
  8.1128 -
  8.1129 -  if (!gst_element_register (plugin, "nuvdemux", GST_RANK_SECONDARY,
  8.1130 -          GST_TYPE_NUV_DEMUX)) {
  8.1131 -    return FALSE;
  8.1132 -  }
  8.1133 -  return TRUE;
  8.1134 -}
  8.1135 -
  8.1136 -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
  8.1137 -    GST_VERSION_MINOR,
  8.1138 -    "nuvdemux",
  8.1139 -    "Demuxes and muxes audio and video",
  8.1140 -    plugin_init, VERSION, "LGPL", "NuvDemux", "")
     9.1 --- a/gst-plugins-nuvdemux/src/gstnuvdemux.h	Thu Nov 09 19:12:55 2006 +0000
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,198 +0,0 @@
     9.4 -/* GStreamer
     9.5 - * Copyright (C) <2006> Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
     9.6 - *                      Rosfran Borges <rosfran.borges@indt.org.br>
     9.7 - *
     9.8 - * This library is free software; you can redistribute it and/or
     9.9 - * modify it under the terms of the GNU Library General Public
    9.10 - * License as published by the Free Software Foundation; either
    9.11 - * version 2 of the License, or (at your option) any later version.
    9.12 - *
    9.13 - * This library is distributed in the hope that it will be useful,
    9.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    9.16 - * Library General Public License for more details.
    9.17 - *
    9.18 - * You should have received a copy of the GNU Library General Public
    9.19 - * License along with this library; if not, write to the
    9.20 - * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    9.21 - * Boston, MA 02111-1307, USA.
    9.22 - */
    9.23 -
    9.24 -#ifndef __GST_NUV_DEMUX_H__
    9.25 -#define __GST_NUV_DEMUX_H__
    9.26 -
    9.27 -#include <gst/gst.h>
    9.28 -
    9.29 -#include <gst/base/gstadapter.h>
    9.30 -
    9.31 -G_BEGIN_DECLS
    9.32 -
    9.33 -#define GST_TYPE_NUV_DEMUX \
    9.34 -  (gst_nuv_demux_get_type ())
    9.35 -#define GST_NUV_DEMUX(obj) \
    9.36 -  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_NUV_DEMUX, GstNuvDemux))
    9.37 -#define GST_NUV_DEMUX_CLASS(klass) \
    9.38 -  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_NUV_DEMUX, GstNuvDemuxClass))
    9.39 -#define GST_IS_NUV_DEMUX(obj) \
    9.40 -  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_NUV_DEMUX))
    9.41 -#define GST_IS_NUV_DEMUX_CLASS(klass) \
    9.42 -  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_NUV_DEMUX))
    9.43 -
    9.44 -#define DEMUX_INDEX_SIZE_MAX (100000)
    9.45 -
    9.46 -/* Indexes (timecodes/offsets) conversion structures */
    9.47 -typedef struct
    9.48 -{
    9.49 -    gint64 i_time;
    9.50 -    gint64 i_offset;
    9.51 -
    9.52 -} nuv_demux_index_entry;
    9.53 -
    9.54 -typedef struct
    9.55 -{
    9.56 -    gint i_idx;
    9.57 -    gint i_idx_max;
    9.58 -
    9.59 -    nuv_demux_index_entry idx[DEMUX_INDEX_SIZE_MAX];
    9.60 -} nuv_demux_index;
    9.61 -
    9.62 -/* */
    9.63 -typedef struct
    9.64 -{
    9.65 -    gchar id[12];       /* "NuppelVideo\0" or "MythTVVideo\0" */
    9.66 -    gchar version[5];    /* "x.xx\0" */
    9.67 -
    9.68 -    gint  i_width;
    9.69 -    gint  i_height;
    9.70 -    gint  i_width_desired;
    9.71 -    gint  i_height_desired;
    9.72 -
    9.73 -    gchar i_mode;            /* P progressive, I interlaced */
    9.74 -
    9.75 -    gdouble  d_aspect;       /* 1.0 squared pixel */
    9.76 -    gdouble  d_fps;
    9.77 -
    9.78 -    gint     i_video_blocks; /* 0 no video, -1 unknown */
    9.79 -    gint     i_audio_blocks;
    9.80 -    gint     i_text_blocks;
    9.81 -
    9.82 -    gint     i_keyframe_distance;
    9.83 -
    9.84 -} nuv_header;
    9.85 -
    9.86 -typedef struct
    9.87 -{
    9.88 -    gchar i_type;        /* A: audio, V: video, S: sync; T: test
    9.89 -                           R: Seekpoint (string:RTjjjjjjjj)
    9.90 -                           D: Extra data for codec */
    9.91 -    gchar i_compression; /* V: 0 uncompressed
    9.92 -                              1 RTJpeg
    9.93 -                              2 RTJpeg+lzo
    9.94 -                              N black frame
    9.95 -                              L copy last
    9.96 -                           A: 0 uncompressed (44100 1-bits, 2ch)
    9.97 -                              1 lzo
    9.98 -                              2 layer 2
    9.99 -                              3 layer 3
   9.100 -                              F flac
   9.101 -                              S shorten
   9.102 -                              N null frame loudless
   9.103 -                              L copy last
   9.104 -                            S: B audio and vdeo sync point
   9.105 -                               A audio sync info (timecode == effective
   9.106 -                                    dsp frequency*100)
   9.107 -                               V next video sync (timecode == next video
   9.108 -                                    frame num)
   9.109 -                               S audio,video,text correlation */
   9.110 -    gchar i_keyframe;    /* 0 keyframe, else no no key frame */
   9.111 -    guint8 i_filters;  /* 0x01: gauss 5 pixel (8,2,2,2,2)/16
   9.112 -                           0x02: gauss 5 pixel (8,1,1,1,1)/12
   9.113 -                           0x04: cartoon filter */
   9.114 -
   9.115 -    gint32 i_timecode;     /* ms */
   9.116 -
   9.117 -    gint i_length;       /* V,A,T: length of following data
   9.118 -                           S: length of packet correl */
   9.119 -} nuv_frame_header;
   9.120 -
   9.121 -/* FIXME Not sure of this one */
   9.122 -typedef struct
   9.123 -{
   9.124 -    gint             i_version;
   9.125 -    guint32		     i_video_fcc;
   9.126 -
   9.127 -    guint32		     i_audio_fcc;
   9.128 -    gint             i_audio_sample_rate;
   9.129 -    gint             i_audio_bits_per_sample;
   9.130 -    gint             i_audio_channels;
   9.131 -    gint             i_audio_compression_ratio;
   9.132 -    gint             i_audio_quality;
   9.133 -    gint             i_rtjpeg_quality;
   9.134 -    gint             i_rtjpeg_luma_filter;
   9.135 -    gint             i_rtjpeg_chroma_filter;
   9.136 -    gint             i_lavc_bitrate;
   9.137 -    gint             i_lavc_qmin;
   9.138 -    gint             i_lavc_qmax;
   9.139 -    gint             i_lavc_maxqdiff;
   9.140 -    gint64         	 i_seekable_offset;
   9.141 -    gint64           i_keyframe_adjust_offset;
   9.142 -
   9.143 -} nuv_extended_header;
   9.144 -
   9.145 -typedef enum {
   9.146 -  GST_NUV_DEMUX_START,
   9.147 -  GST_NUV_DEMUX_HEADER_DATA,
   9.148 -  GST_NUV_DEMUX_EXTRA_DATA,
   9.149 -  GST_NUV_DEMUX_MPEG_DATA,
   9.150 -  GST_NUV_DEMUX_EXTEND_HEADER,
   9.151 -  GST_NUV_DEMUX_EXTEND_HEADER_DATA,
   9.152 -  GST_NUV_DEMUX_FRAME_HEADER,
   9.153 -  GST_NUV_DEMUX_MOVI,
   9.154 -  GST_NUV_DEMUX_INVALID_DATA
   9.155 -} GstNuvDemuxState;
   9.156 -
   9.157 -typedef struct _GstNuvDemux {
   9.158 -  GstElement     parent;
   9.159 -
   9.160 -  guint         mode;
   9.161 -  GstAdapter    *adapter; 
   9.162 -  guint64       video_offset;
   9.163 -  guint64       audio_offset;
   9.164 -
   9.165 -  /* pads */
   9.166 -  
   9.167 -  GstPad        *sinkpad;
   9.168 -  GstPad        *src_video_pad;  
   9.169 -  GstPad        *src_audio_pad;
   9.170 -  gboolean      first_video;
   9.171 -  gboolean      first_audio;
   9.172 -
   9.173 -  /* NUV decoding state */
   9.174 -  GstNuvDemuxState state;
   9.175 -  guint64        offset;
   9.176 -
   9.177 -  /* Mpeg ExtraData */
   9.178 -  guint64       mpeg_data_size;
   9.179 -  GstBuffer     *mpeg_buffer;
   9.180 -  
   9.181 -  nuv_header *h;
   9.182 -  nuv_extended_header *eh;
   9.183 -  nuv_frame_header *fh;
   9.184 -  
   9.185 -  /* index */
   9.186 -  nuv_demux_index *index_entries;
   9.187 -  guint          index_size;
   9.188 -  guint64        index_offset;
   9.189 -  guint          current_entry;
   9.190 -
   9.191 -} GstNuvDemux;
   9.192 -
   9.193 -typedef struct _GstNuvDemuxClass {
   9.194 -  GstElementClass parent_class;
   9.195 -} GstNuvDemuxClass;
   9.196 -
   9.197 -GType           gst_nuv_demux_get_type          (void);
   9.198 -
   9.199 -G_END_DECLS
   9.200 -
   9.201 -#endif /* __GST_NUV_DEMUX_H__ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/gst-plugins-nuvdemux/typefind/Makefile.am	Thu Nov 09 19:45:27 2006 +0000
    10.3 @@ -0,0 +1,14 @@
    10.4 +plugin_LTLIBRARIES = libgsttypefindfunctions.la
    10.5 +
    10.6 +libgsttypefindfunctions_la_SOURCES = \
    10.7 +	gsttypefindfunctions.c
    10.8 +
    10.9 +libgsttypefindfunctions_la_CFLAGS = \
   10.10 +	$(GST_CFLAGS)
   10.11 +
   10.12 +libgsttypefindfunctions_la_LDFLAGS = \
   10.13 +	$(GST_PLUGIN_LDFLAGS) \
   10.14 +	$(GST_BASE_LIBS)
   10.15 +
   10.16 +libgsttypefindfunctions_la_LIBADD = \
   10.17 +	$(GST_LIBS)
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/gst-plugins-nuvdemux/typefind/gsttypefindfunctions.c	Thu Nov 09 19:45:27 2006 +0000
    11.3 @@ -0,0 +1,2808 @@
    11.4 +/* GStreamer
    11.5 + * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
    11.6 + *
    11.7 + * gsttypefindfunctions.c: collection of various typefind functions
    11.8 + *
    11.9 + * This library is free software; you can redistribute it and/or
   11.10 + * modify it under the terms of the GNU Library General Public
   11.11 + * License as published by the Free Software Foundation; either
   11.12 + * version 2 of the License, or (at your option) any later version.
   11.13 + *
   11.14 + * This library is distributed in the hope that it will be useful,
   11.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11.17 + * Library General Public License for more details.
   11.18 + *
   11.19 + * You should have received a copy of the GNU Library General Public
   11.20 + * License along with this library; if not, write to the
   11.21 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   11.22 + * Boston, MA 02111-1307, USA.
   11.23 + */
   11.24 +
   11.25 +#ifdef HAVE_CONFIG_H
   11.26 +#include "config.h"
   11.27 +#endif
   11.28 +
   11.29 +#include <glib/gstrfuncs.h>
   11.30 +
   11.31 +#include <gst/gsttypefind.h>
   11.32 +#include <gst/gstelement.h>
   11.33 +#include <gst/gstversion.h>
   11.34 +#include <gst/gstinfo.h>
   11.35 +#include <gst/gstutils.h>
   11.36 +
   11.37 +#include <string.h>
   11.38 +#include <ctype.h>
   11.39 +
   11.40 +GST_DEBUG_CATEGORY_STATIC (type_find_debug);
   11.41 +#define GST_CAT_DEFAULT type_find_debug
   11.42 +
   11.43 +/*** text/plain ***/
   11.44 +static gboolean xml_check_first_element (GstTypeFind * tf,
   11.45 +    const gchar * element, guint elen, gboolean strict);
   11.46 +
   11.47 +
   11.48 +static GstStaticCaps utf8_caps = GST_STATIC_CAPS ("text/plain");
   11.49 +
   11.50 +#define UTF8_CAPS gst_static_caps_get(&utf8_caps)
   11.51 +
   11.52 +static gboolean
   11.53 +utf8_type_find_have_valid_utf8_at_offset (GstTypeFind * tf, guint64 offset,
   11.54 +    GstTypeFindProbability * prob)
   11.55 +{
   11.56 +  guint8 *data;
   11.57 +
   11.58 +  /* randomly decided values */
   11.59 +  guint min_size = 16;          /* minimum size  */
   11.60 +  guint size = 32 * 1024;       /* starting size */
   11.61 +  guint probability = 95;       /* starting probability */
   11.62 +  guint step = 10;              /* how much we reduce probability in each
   11.63 +                                 * iteration */
   11.64 +
   11.65 +  while (probability > step && size > min_size) {
   11.66 +    data = gst_type_find_peek (tf, offset, size);
   11.67 +    if (data) {
   11.68 +      gchar *end;
   11.69 +      gchar *start = (gchar *) data;
   11.70 +
   11.71 +      if (g_utf8_validate (start, size, (const gchar **) &end) || (end - start + 4 > size)) {   /* allow last char to be cut off */
   11.72 +        *prob = probability;
   11.73 +        return TRUE;
   11.74 +      }
   11.75 +      *prob = 0;
   11.76 +      return FALSE;
   11.77 +    }
   11.78 +    size /= 2;
   11.79 +    probability -= step;
   11.80 +  }
   11.81 +  *prob = 0;
   11.82 +  return FALSE;
   11.83 +}
   11.84 +
   11.85 +static void
   11.86 +utf8_type_find (GstTypeFind * tf, gpointer unused)
   11.87 +{
   11.88 +  GstTypeFindProbability start_prob, mid_prob;
   11.89 +  guint64 length;
   11.90 +
   11.91 +  /* leave xml to the xml typefinders */
   11.92 +  if (xml_check_first_element (tf, "", 0, TRUE))
   11.93 +    return;
   11.94 +
   11.95 +  /* check beginning of stream */
   11.96 +  if (!utf8_type_find_have_valid_utf8_at_offset (tf, 0, &start_prob))
   11.97 +    return;
   11.98 +
   11.99 +  GST_LOG ("start is plain text with probability of %u", start_prob);
  11.100 +
  11.101 +  /* POSSIBLE is the highest probability we ever return if we can't
  11.102 +   * probe into the middle of the file and don't know its length */
  11.103 +
  11.104 +  length = gst_type_find_get_length (tf);
  11.105 +  if (length == 0 || length == (guint64) - 1) {
  11.106 +    gst_type_find_suggest (tf, MIN (start_prob, GST_TYPE_FIND_POSSIBLE),
  11.107 +        UTF8_CAPS);
  11.108 +    return;
  11.109 +  }
  11.110 +
  11.111 +  if (length < 64 * 1024) {
  11.112 +    gst_type_find_suggest (tf, start_prob, UTF8_CAPS);
  11.113 +    return;
  11.114 +  }
  11.115 +
  11.116 +  /* check middle of stream */
  11.117 +  if (!utf8_type_find_have_valid_utf8_at_offset (tf, length / 2, &mid_prob))
  11.118 +    return;
  11.119 +
  11.120 +  GST_LOG ("middle is plain text with probability of %u", mid_prob);
  11.121 +  gst_type_find_suggest (tf, (start_prob + mid_prob) / 2, UTF8_CAPS);
  11.122 +}
  11.123 +
  11.124 +/*** text/uri-list ***/
  11.125 +
  11.126 +static GstStaticCaps uri_caps = GST_STATIC_CAPS ("text/uri-list");
  11.127 +
  11.128 +#define URI_CAPS (gst_static_caps_get(&uri_caps))
  11.129 +#define BUFFER_SIZE 16          /* If the string is < 16 bytes we're screwed */
  11.130 +#define INC_BUFFER {                                                    \
  11.131 +  pos++;                                                                \
  11.132 +  if (pos == BUFFER_SIZE) {                                             \
  11.133 +    pos = 0;                                                            \
  11.134 +    offset += BUFFER_SIZE;                                              \
  11.135 +    data = gst_type_find_peek (tf, offset, BUFFER_SIZE);                \
  11.136 +    if (data == NULL) return;                                           \
  11.137 +  } else {                                                              \
  11.138 +    data++;                                                             \
  11.139 +  }                                                                     \
  11.140 +}
  11.141 +static void
  11.142 +uri_type_find (GstTypeFind * tf, gpointer unused)
  11.143 +{
  11.144 +  guint8 *data = gst_type_find_peek (tf, 0, BUFFER_SIZE);
  11.145 +  guint pos = 0;
  11.146 +  guint offset = 0;
  11.147 +
  11.148 +  if (data) {
  11.149 +    /* Search for # comment lines */
  11.150 +    while (*data == '#') {
  11.151 +      /* Goto end of line */
  11.152 +      while (*data != '\n') {
  11.153 +        INC_BUFFER;
  11.154 +      }
  11.155 +
  11.156 +      INC_BUFFER;
  11.157 +    }
  11.158 +
  11.159 +    if (!g_ascii_isalpha (*data)) {
  11.160 +      /* Had a non alpha char - can't be uri-list */
  11.161 +      return;
  11.162 +    }
  11.163 +
  11.164 +    INC_BUFFER;
  11.165 +
  11.166 +    while (g_ascii_isalnum (*data)) {
  11.167 +      INC_BUFFER;
  11.168 +    }
  11.169 +
  11.170 +    if (*data != ':') {
  11.171 +      /* First non alpha char is not a : */
  11.172 +      return;
  11.173 +    }
  11.174 +
  11.175 +    /* Get the next 2 bytes as well */
  11.176 +    data = gst_type_find_peek (tf, offset + pos, 3);
  11.177 +    if (data == NULL)
  11.178 +      return;
  11.179 +
  11.180 +    if (data[1] != '/' && data[2] != '/') {
  11.181 +      return;
  11.182 +    }
  11.183 +
  11.184 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, URI_CAPS);
  11.185 +  }
  11.186 +}
  11.187 +
  11.188 +
  11.189 +/*** application/xml **********************************************************/
  11.190 +
  11.191 +#define XML_BUFFER_SIZE 16
  11.192 +#define XML_INC_BUFFER {                                                \
  11.193 +  pos++;                                                                \
  11.194 +  if (pos == XML_BUFFER_SIZE) {                                         \
  11.195 +    pos = 0;                                                            \
  11.196 +    offset += XML_BUFFER_SIZE;                                          \
  11.197 +    data = gst_type_find_peek (tf, offset, XML_BUFFER_SIZE);            \
  11.198 +    if (data == NULL) return FALSE;                                     \
  11.199 +  } else {                                                              \
  11.200 +    data++;                                                             \
  11.201 +  }                                                                     \
  11.202 +}
  11.203 +
  11.204 +static gboolean
  11.205 +xml_check_first_element (GstTypeFind * tf, const gchar * element, guint elen,
  11.206 +    gboolean strict)
  11.207 +{
  11.208 +  gboolean got_xmldec;
  11.209 +  guint8 *data;
  11.210 +  guint offset = 0;
  11.211 +  guint pos = 0;
  11.212 +
  11.213 +  data = gst_type_find_peek (tf, 0, XML_BUFFER_SIZE);
  11.214 +  if (!data)
  11.215 +    return FALSE;
  11.216 +
  11.217 +  /* look for the XMLDec
  11.218 +   * see XML spec 2.8, Prolog and Document Type Declaration
  11.219 +   * http://www.w3.org/TR/2004/REC-xml-20040204/#sec-prolog-dtd */
  11.220 +  got_xmldec = (memcmp (data, "<?xml", 5) == 0);
  11.221 +
  11.222 +  if (strict && !got_xmldec)
  11.223 +    return FALSE;
  11.224 +
  11.225 +  /* skip XMLDec in any case if we've got one */
  11.226 +  if (got_xmldec) {
  11.227 +    pos += 5;
  11.228 +    data += 5;
  11.229 +  }
  11.230 +
  11.231 +  /* look for the first element, it has to be the requested element. Bail
  11.232 +   * out if it is not within the first 4kB. */
  11.233 +  while (data && (offset + pos) < 4096) {
  11.234 +    while (*data != '<' && (offset + pos) < 4096) {
  11.235 +      XML_INC_BUFFER;
  11.236 +    }
  11.237 +
  11.238 +    XML_INC_BUFFER;
  11.239 +    if (!g_ascii_isalpha (*data)) {
  11.240 +      /* if not alphabetic, it's a PI or an element / attribute declaration
  11.241 +       * like <?xxx or <!xxx */
  11.242 +      XML_INC_BUFFER;
  11.243 +      continue;
  11.244 +    }
  11.245 +
  11.246 +    /* the first normal element, check if it's the one asked for */
  11.247 +    data = gst_type_find_peek (tf, offset + pos, elen + 1);
  11.248 +    return (data && element && strncmp ((char *) data, element, elen) == 0);
  11.249 +  }
  11.250 +
  11.251 +  return FALSE;
  11.252 +}
  11.253 +
  11.254 +static GstStaticCaps generic_xml_caps = GST_STATIC_CAPS ("application/xml");
  11.255 +
  11.256 +#define GENERIC_XML_CAPS (gst_static_caps_get(&generic_xml_caps))
  11.257 +static void
  11.258 +xml_type_find (GstTypeFind * tf, gpointer unused)
  11.259 +{
  11.260 +  if (xml_check_first_element (tf, "", 0, TRUE)) {
  11.261 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MINIMUM, GENERIC_XML_CAPS);
  11.262 +  }
  11.263 +}
  11.264 +
  11.265 +/*** application/smil *********************************************************/
  11.266 +
  11.267 +static GstStaticCaps smil_caps = GST_STATIC_CAPS ("application/smil");
  11.268 +
  11.269 +#define SMIL_CAPS (gst_static_caps_get(&smil_caps))
  11.270 +static void
  11.271 +smil_type_find (GstTypeFind * tf, gpointer unused)
  11.272 +{
  11.273 +  if (xml_check_first_element (tf, "smil", 4, FALSE)) {
  11.274 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SMIL_CAPS);
  11.275 +  }
  11.276 +}
  11.277 +
  11.278 +/*** text/html ***/
  11.279 +
  11.280 +static GstStaticCaps html_caps = GST_STATIC_CAPS ("text/html");
  11.281 +
  11.282 +#define HTML_CAPS gst_static_caps_get (&html_caps)
  11.283 +
  11.284 +static void
  11.285 +html_type_find (GstTypeFind * tf, gpointer unused)
  11.286 +{
  11.287 +  gchar *d, *data;
  11.288 +
  11.289 +  data = (gchar *) gst_type_find_peek (tf, 0, 16);
  11.290 +  if (!data)
  11.291 +    return;
  11.292 +
  11.293 +  if (!g_ascii_strncasecmp (data, "<!DOCTYPE HTML", 14)) {
  11.294 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, HTML_CAPS);
  11.295 +  } else if (xml_check_first_element (tf, "html", 4, FALSE)) {
  11.296 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, HTML_CAPS);
  11.297 +  } else if ((d = memchr (data, '<', 16))) {
  11.298 +    data = (gchar *) gst_type_find_peek (tf, d - data, 6);
  11.299 +    if (data && g_ascii_strncasecmp (data, "<html>", 6) == 0) {
  11.300 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, HTML_CAPS);
  11.301 +    }
  11.302 +  }
  11.303 +}
  11.304 +
  11.305 +/*** video/x-fli ***/
  11.306 +
  11.307 +static GstStaticCaps flx_caps = GST_STATIC_CAPS ("video/x-fli");
  11.308 +
  11.309 +#define FLX_CAPS gst_static_caps_get(&flx_caps)
  11.310 +static void
  11.311 +flx_type_find (GstTypeFind * tf, gpointer unused)
  11.312 +{
  11.313 +  guint8 *data = gst_type_find_peek (tf, 0, 134);
  11.314 +
  11.315 +  if (data) {
  11.316 +    /* check magic and the frame type of the first frame */
  11.317 +    if ((data[4] == 0x11 || data[4] == 0x12 ||
  11.318 +            data[4] == 0x30 || data[4] == 0x44) &&
  11.319 +        data[5] == 0xaf &&
  11.320 +        ((data[132] == 0x00 || data[132] == 0xfa) && data[133] == 0xf1)) {
  11.321 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, FLX_CAPS);
  11.322 +    }
  11.323 +    return;
  11.324 +  }
  11.325 +  data = gst_type_find_peek (tf, 0, 6);
  11.326 +  if (data) {
  11.327 +    /* check magic only */
  11.328 +    if ((data[4] == 0x11 || data[4] == 0x12 ||
  11.329 +            data[4] == 0x30 || data[4] == 0x44) && data[5] == 0xaf) {
  11.330 +      gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, FLX_CAPS);
  11.331 +    }
  11.332 +    return;
  11.333 +  }
  11.334 +}
  11.335 +
  11.336 +/*** application/x-id3 ***/
  11.337 +
  11.338 +static GstStaticCaps id3_caps = GST_STATIC_CAPS ("application/x-id3");
  11.339 +
  11.340 +#define ID3_CAPS gst_static_caps_get(&id3_caps)
  11.341 +static void
  11.342 +id3v2_type_find (GstTypeFind * tf, gpointer unused)
  11.343 +{
  11.344 +  guint8 *data = gst_type_find_peek (tf, 0, 10);
  11.345 +
  11.346 +  if (data && memcmp (data, "ID3", 3) == 0 &&
  11.347 +      data[3] != 0xFF && data[4] != 0xFF &&
  11.348 +      (data[6] & 0x80) == 0 && (data[7] & 0x80) == 0 &&
  11.349 +      (data[8] & 0x80) == 0 && (data[9] & 0x80) == 0) {
  11.350 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, ID3_CAPS);
  11.351 +  }
  11.352 +}
  11.353 +
  11.354 +static void
  11.355 +id3v1_type_find (GstTypeFind * tf, gpointer unused)
  11.356 +{
  11.357 +  guint8 *data = gst_type_find_peek (tf, -128, 3);
  11.358 +
  11.359 +  if (data && memcmp (data, "TAG", 3) == 0) {
  11.360 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, ID3_CAPS);
  11.361 +  }
  11.362 +}
  11.363 +
  11.364 +/*** application/x-ape ***/
  11.365 +
  11.366 +static GstStaticCaps apetag_caps = GST_STATIC_CAPS ("application/x-apetag");
  11.367 +
  11.368 +#define APETAG_CAPS gst_static_caps_get(&apetag_caps)
  11.369 +static void
  11.370 +apetag_type_find (GstTypeFind * tf, gpointer unused)
  11.371 +{
  11.372 +  guint8 *data;
  11.373 +
  11.374 +  /* APEv1/2 at start of file */
  11.375 +  data = gst_type_find_peek (tf, 0, 8);
  11.376 +  if (data && !memcmp (data, "APETAGEX", 8)) {
  11.377 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, APETAG_CAPS);
  11.378 +    return;
  11.379 +  }
  11.380 +
  11.381 +  /* APEv1/2 at end of file */
  11.382 +  data = gst_type_find_peek (tf, -32, 8);
  11.383 +  if (data && !memcmp (data, "APETAGEX", 8)) {
  11.384 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, APETAG_CAPS);
  11.385 +    return;
  11.386 +  }
  11.387 +}
  11.388 +
  11.389 +/*** audio/x-ttafile ***/
  11.390 +
  11.391 +static GstStaticCaps tta_caps = GST_STATIC_CAPS ("audio/x-ttafile");
  11.392 +
  11.393 +#define TTA_CAPS gst_static_caps_get(&tta_caps)
  11.394 +static void
  11.395 +tta_type_find (GstTypeFind * tf, gpointer unused)
  11.396 +{
  11.397 +  guint8 *data = gst_type_find_peek (tf, 0, 3);
  11.398 +
  11.399 +  if (data) {
  11.400 +    if (memcmp (data, "TTA", 3) == 0) {
  11.401 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, TTA_CAPS);
  11.402 +      return;
  11.403 +    }
  11.404 +  }
  11.405 +}
  11.406 +
  11.407 +/*** audio/mpeg version 2, 4 ***/
  11.408 +
  11.409 +static GstStaticCaps aac_caps = GST_STATIC_CAPS ("audio/mpeg, "
  11.410 +    "mpegversion = (int) { 2, 4 }, framed = (bool) false");
  11.411 +#define AAC_CAPS (gst_static_caps_get(&aac_caps))
  11.412 +#define AAC_AMOUNT (4096)
  11.413 +static void
  11.414 +aac_type_find (GstTypeFind * tf, gpointer unused)
  11.415 +{
  11.416 +  guint8 *data = gst_type_find_peek (tf, 0, AAC_AMOUNT);
  11.417 +  gint snc;
  11.418 +
  11.419 +  /* detect adts header or adif header.
  11.420 +   * The ADIF header is 4 bytes, that should be OK. The ADTS header, on
  11.421 +   * the other hand, is 14 bits only, so we require one valid frame with
  11.422 +   * again a valid syncpoint on the next one (28 bits) for certainty. We
  11.423 +   * require 4 kB, which is quite a lot, since frames are generally 200-400
  11.424 +   * bytes.
  11.425 +   */
  11.426 +  if (data) {
  11.427 +    gint n;
  11.428 +
  11.429 +    for (n = 0; n < AAC_AMOUNT - 3; n++) {
  11.430 +      snc = GST_READ_UINT16_BE (&data[n]);
  11.431 +      if ((snc & 0xfff6) == 0xfff0) {
  11.432 +        /* ADTS header - find frame length */
  11.433 +        gint len;
  11.434 +
  11.435 +        GST_DEBUG ("Found one ADTS syncpoint at offset 0x%x, tracing next...",
  11.436 +            n);
  11.437 +        if (AAC_AMOUNT - n < 5) {
  11.438 +          GST_DEBUG ("Not enough data to parse ADTS header");
  11.439 +          break;
  11.440 +        }
  11.441 +        len = ((data[n + 3] & 0x03) << 11) |
  11.442 +            (data[n + 4] << 3) | ((data[n + 5] & 0xe0) >> 5);
  11.443 +        if (n + len + 2 >= AAC_AMOUNT) {
  11.444 +          GST_DEBUG ("Next frame is not within reach");
  11.445 +          break;
  11.446 +        } else if (len == 0) {
  11.447 +          continue;
  11.448 +        }
  11.449 +
  11.450 +        snc = GST_READ_UINT16_BE (&data[n + len]);
  11.451 +        if ((snc & 0xfff6) == 0xfff0) {
  11.452 +          gint mpegversion = (data[n + 1] & 0x08) ? 2 : 4;
  11.453 +          GstCaps *caps = gst_caps_new_simple ("audio/mpeg",
  11.454 +              "framed", G_TYPE_BOOLEAN, FALSE,
  11.455 +              "mpegversion", G_TYPE_INT, mpegversion,
  11.456 +              NULL);
  11.457 +
  11.458 +          gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, caps);
  11.459 +          gst_caps_unref (caps);
  11.460 +
  11.461 +          GST_DEBUG ("Found ADTS-%d syncpoint at offset 0x%x (framelen %u)",
  11.462 +              mpegversion, n, len);
  11.463 +          break;
  11.464 +        }
  11.465 +
  11.466 +        GST_DEBUG ("No next frame found... (should be at 0x%x)", n + len);
  11.467 +      } else if (!memcmp (&data[n], "ADIF", 4)) {
  11.468 +        /* ADIF header */
  11.469 +        GstCaps *caps = gst_caps_new_simple ("audio/mpeg",
  11.470 +            "framed", G_TYPE_BOOLEAN, FALSE,
  11.471 +            "mpegversion", G_TYPE_INT, 4,
  11.472 +            NULL);
  11.473 +
  11.474 +        gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, caps);
  11.475 +        gst_caps_unref (caps);
  11.476 +      }
  11.477 +    }
  11.478 +  }
  11.479 +}
  11.480 +
  11.481 +/*** audio/mpeg version 1 ***/
  11.482 +
  11.483 +/*
  11.484 + * The chance that random data is identified as a valid mp3 header is 63 / 2^18
  11.485 + * (0.024%) per try. This makes the function for calculating false positives
  11.486 + *   1 - (1 - ((63 / 2 ^18) ^ GST_MP3_TYPEFIND_MIN_HEADERS)) ^ buffersize)
  11.487 + * This has the following probabilities of false positives:
  11.488 + * datasize               MIN_HEADERS
  11.489 + * (bytes)      1       2       3       4
  11.490 + * 4096         62.6%    0.02%   0%      0%
  11.491 + * 16384        98%      0.09%   0%      0%
  11.492 + * 1 MiB       100%      5.88%   0%      0%
  11.493 + * 1 GiB       100%    100%      1.44%   0%
  11.494 + * 1 TiB       100%    100%    100%      0.35%
  11.495 + * This means that the current choice (3 headers by most of the time 4096 byte
  11.496 + * buffers is pretty safe for now.
  11.497 + *
  11.498 + * The max. size of each frame is 1440 bytes, which means that for N frames to
  11.499 + * be detected, we need 1440 * GST_MP3_TYPEFIND_MIN_HEADERS + 3 bytes of data.
  11.500 + * Assuming we step into the stream right after the frame header, this
  11.501 + * means we need 1440 * (GST_MP3_TYPEFIND_MIN_HEADERS + 1) - 1 + 3 bytes
  11.502 + * of data (5762) to always detect any mp3.
  11.503 + */
  11.504 +
  11.505 +static const guint mp3types_bitrates[2][3][16] =
  11.506 +    { {{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
  11.507 +    {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
  11.508 +    {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}},
  11.509 +{{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
  11.510 +    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
  11.511 +    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}},
  11.512 +};
  11.513 +
  11.514 +static const guint mp3types_freqs[3][3] = { {11025, 12000, 8000},
  11.515 +{22050, 24000, 16000},
  11.516 +{44100, 48000, 32000}
  11.517 +};
  11.518 +
  11.519 +static inline guint
  11.520 +mp3_type_frame_length_from_header (guint32 header, guint * put_layer,
  11.521 +    guint * put_channels, guint * put_bitrate, guint * put_samplerate,
  11.522 +    gboolean * may_be_free_format, gint possible_free_framelen)
  11.523 +{
  11.524 +  guint bitrate, layer, length, mode, samplerate, version, channels;
  11.525 +
  11.526 +  if ((header & 0xffe00000) != 0xffe00000)
  11.527 +    return 0;
  11.528 +
  11.529 +  /* we don't need extension, copyright, original or
  11.530 +   * emphasis for the frame length */
  11.531 +  header >>= 6;
  11.532 +
  11.533 +  /* mode */
  11.534 +  mode = header & 0x3;
  11.535 +  header >>= 3;
  11.536 +
  11.537 +  /* padding */
  11.538 +  length = header & 0x1;
  11.539 +  header >>= 1;
  11.540 +
  11.541 +  /* sampling frequency */
  11.542 +  samplerate = header & 0x3;
  11.543 +  if (samplerate == 3)
  11.544 +    return 0;
  11.545 +  header >>= 2;
  11.546 +
  11.547 +  /* bitrate index */
  11.548 +  bitrate = header & 0xF;
  11.549 +  if (bitrate == 0 && possible_free_framelen == -1) {
  11.550 +    GST_LOG ("Possibly a free format mp3 - signalling");
  11.551 +    *may_be_free_format = TRUE;
  11.552 +  }
  11.553 +  if (bitrate == 15 || (bitrate == 0 && possible_free_framelen == -1))
  11.554 +    return 0;
  11.555 +
  11.556 +  /* ignore error correction, too */
  11.557 +  header >>= 5;
  11.558 +
  11.559 +  /* layer */
  11.560 +  layer = 4 - (header & 0x3);
  11.561 +  if (layer == 4)
  11.562 +    return 0;
  11.563 +  header >>= 2;
  11.564 +
  11.565 +  /* version 0=MPEG2.5; 2=MPEG2; 3=MPEG1 */
  11.566 +  version = header & 0x3;
  11.567 +  if (version == 1)
  11.568 +    return 0;
  11.569 +
  11.570 +  /* lookup */
  11.571 +  channels = (mode == 3) ? 1 : 2;
  11.572 +  samplerate = mp3types_freqs[version > 0 ? version - 1 : 0][samplerate];
  11.573 +  if (bitrate == 0) {
  11.574 +    if (layer == 1) {
  11.575 +      length *= 4;
  11.576 +      length += possible_free_framelen;
  11.577 +      bitrate = length * samplerate / 48000;
  11.578 +    } else {
  11.579 +      length += possible_free_framelen;
  11.580 +      bitrate = length * samplerate /
  11.581 +          ((layer == 3 && version != 3) ? 72000 : 144000);
  11.582 +    }
  11.583 +  } else {
  11.584 +    /* calculating */
  11.585 +    bitrate = mp3types_bitrates[version == 3 ? 0 : 1][layer - 1][bitrate];
  11.586 +    if (layer == 1) {
  11.587 +      length = ((12000 * bitrate / samplerate) + length) * 4;
  11.588 +    } else {
  11.589 +      length += ((layer == 3
  11.590 +              && version != 3) ? 72000 : 144000) * bitrate / samplerate;
  11.591 +    }
  11.592 +  }
  11.593 +
  11.594 +  GST_LOG ("mp3typefind: calculated mp3 frame length of %u bytes", length);
  11.595 +  GST_LOG
  11.596 +      ("mp3typefind: samplerate = %u - bitrate = %u - layer = %u - version = %u"
  11.597 +      " - channels = %u", samplerate, bitrate, layer, version, channels);
  11.598 +
  11.599 +  if (put_layer)
  11.600 +    *put_layer = layer;
  11.601 +  if (put_channels)
  11.602 +    *put_channels = channels;
  11.603 +  if (put_bitrate)
  11.604 +    *put_bitrate = bitrate;
  11.605 +  if (put_samplerate)
  11.606 +    *put_samplerate = samplerate;
  11.607 +
  11.608 +  return length;
  11.609 +}
  11.610 +
  11.611 +
  11.612 +static GstStaticCaps mp3_caps = GST_STATIC_CAPS ("audio/mpeg, "
  11.613 +    "mpegversion = (int) 1, layer = (int) [ 1, 3 ]");
  11.614 +#define MP3_CAPS (gst_static_caps_get(&mp3_caps))
  11.615 +/*
  11.616 + * random values for typefinding
  11.617 + * if no more data is available, we will return a probability of
  11.618 + * (found_headers/TRY_HEADERS) * (MAXIMUM * (TRY_SYNC - bytes_skipped)
  11.619 + *        / TRY_SYNC)
  11.620 + * if found_headers >= MIN_HEADERS
  11.621 + */
  11.622 +#define GST_MP3_TYPEFIND_MIN_HEADERS (2)
  11.623 +#define GST_MP3_TYPEFIND_TRY_HEADERS (5)
  11.624 +#define GST_MP3_TYPEFIND_TRY_SYNC (GST_TYPE_FIND_MAXIMUM * 100) /* 10kB */
  11.625 +#define GST_MP3_TYPEFIND_SYNC_SIZE (2048)
  11.626 +#define GST_MP3_WRONG_HEADER (10)
  11.627 +
  11.628 +static void
  11.629 +mp3_type_find_at_offset (GstTypeFind * tf, guint64 start_off,
  11.630 +    guint * found_layer, GstTypeFindProbability * found_prob)
  11.631 +{
  11.632 +  guint8 *data = NULL;
  11.633 +  guint8 *data_end = NULL;
  11.634 +  guint size;
  11.635 +  guint64 skipped;
  11.636 +  gint last_free_offset = -1;
  11.637 +  gint last_free_framelen = -1;
  11.638 +  gboolean headerstart = TRUE;
  11.639 +
  11.640 +  *found_layer = 0;
  11.641 +  *found_prob = 0;
  11.642 +
  11.643 +  size = 0;
  11.644 +  skipped = 0;
  11.645 +  while (skipped < GST_MP3_TYPEFIND_TRY_SYNC) {
  11.646 +    if (size <= 0) {
  11.647 +      size = GST_MP3_TYPEFIND_SYNC_SIZE * 2;
  11.648 +      do {
  11.649 +        size /= 2;
  11.650 +        data = gst_type_find_peek (tf, skipped + start_off, size);
  11.651 +      } while (size > 10 && !data);
  11.652 +      if (!data)
  11.653 +        break;
  11.654 +      data_end = data + size;
  11.655 +    }
  11.656 +    if (*data == 0xFF) {
  11.657 +      guint8 *head_data = NULL;
  11.658 +      guint layer = 0, bitrate, samplerate, channels;
  11.659 +      guint found = 0;          /* number of valid headers found */
  11.660 +      guint64 offset = skipped;
  11.661 +
  11.662 +      while (found < GST_MP3_TYPEFIND_TRY_HEADERS) {
  11.663 +        guint32 head;
  11.664 +        guint length;
  11.665 +        guint prev_layer = 0, prev_bitrate = 0;
  11.666 +        guint prev_channels = 0, prev_samplerate = 0;
  11.667 +        gboolean free = FALSE;
  11.668 +
  11.669 +        if ((gint64) (offset - skipped + 4) >= 0 &&
  11.670 +            data + offset - skipped + 4 < data_end) {
  11.671 +          head_data = data + offset - skipped;
  11.672 +        } else {
  11.673 +          head_data = gst_type_find_peek (tf, offset + start_off, 4);
  11.674 +        }
  11.675 +        if (!head_data)
  11.676 +          break;
  11.677 +        head = GST_READ_UINT32_BE (head_data);
  11.678 +        if (!(length = mp3_type_frame_length_from_header (head, &layer,
  11.679 +                    &channels, &bitrate, &samplerate, &free,
  11.680 +                    last_free_framelen))) {
  11.681 +          if (free) {
  11.682 +            if (last_free_offset == -1)
  11.683 +              last_free_offset = offset;
  11.684 +            else {
  11.685 +              last_free_framelen = offset - last_free_offset;
  11.686 +              offset = last_free_offset;
  11.687 +              continue;
  11.688 +            }
  11.689 +          } else {
  11.690 +            last_free_framelen = -1;
  11.691 +          }
  11.692 +
  11.693 +          /* Mark the fact that we didn't find a valid header at the beginning */
  11.694 +          if (found == 0)
  11.695 +            headerstart = FALSE;
  11.696 +
  11.697 +          GST_LOG ("%d. header at offset %" G_GUINT64_FORMAT
  11.698 +              " (0x%" G_GINT64_MODIFIER "x) was not an mp3 header "
  11.699 +              "(possibly-free: %s)", found + 1, start_off + offset,
  11.700 +              start_off + offset, free ? "yes" : "no");
  11.701 +          break;
  11.702 +        }
  11.703 +        if ((prev_layer && prev_layer != layer) ||
  11.704 +            /* (prev_bitrate && prev_bitrate != bitrate) || <-- VBR */
  11.705 +            (prev_samplerate && prev_samplerate != samplerate) ||
  11.706 +            (prev_channels && prev_channels != channels)) {
  11.707 +          /* this means an invalid property, or a change, which might mean
  11.708 +           * that this is not a mp3 but just a random bytestream. It could
  11.709 +           * be a freaking funky encoded mp3 though. We'll just not count
  11.710 +           * this header*/
  11.711 +          prev_layer = layer;
  11.712 +          prev_bitrate = bitrate;
  11.713 +          prev_channels = channels;
  11.714 +          prev_samplerate = samplerate;
  11.715 +        } else {
  11.716 +          found++;
  11.717 +          GST_LOG ("found %d. header at offset %" G_GUINT64_FORMAT " (0x%"
  11.718 +              G_GINT64_MODIFIER "X)", found, start_off + offset,
  11.719 +              start_off + offset);
  11.720 +        }
  11.721 +        offset += length;
  11.722 +      }
  11.723 +      g_assert (found <= GST_MP3_TYPEFIND_TRY_HEADERS);
  11.724 +      if (found == GST_MP3_TYPEFIND_TRY_HEADERS ||
  11.725 +          (found >= GST_MP3_TYPEFIND_MIN_HEADERS && head_data == NULL)) {
  11.726 +        /* we can make a valid guess */
  11.727 +        guint probability = found * GST_TYPE_FIND_MAXIMUM *
  11.728 +            (GST_MP3_TYPEFIND_TRY_SYNC - skipped) /
  11.729 +            GST_MP3_TYPEFIND_TRY_HEADERS / GST_MP3_TYPEFIND_TRY_SYNC;
  11.730 +
  11.731 +        if (!headerstart
  11.732 +            && ((probability - GST_MP3_WRONG_HEADER) > GST_TYPE_FIND_MINIMUM))
  11.733 +          probability -= GST_MP3_WRONG_HEADER;
  11.734 +        if (probability < GST_TYPE_FIND_MINIMUM)
  11.735 +          probability = GST_TYPE_FIND_MINIMUM;
  11.736 +        if (start_off > 0)
  11.737 +          probability /= 2;
  11.738 +
  11.739 +        GST_INFO
  11.740 +            ("audio/mpeg calculated %u  =  %u  *  %u / %u  *  (%u - %"
  11.741 +            G_GUINT64_FORMAT ") / %u", probability, GST_TYPE_FIND_MAXIMUM,
  11.742 +            found, GST_MP3_TYPEFIND_TRY_HEADERS, GST_MP3_TYPEFIND_TRY_SYNC,
  11.743 +            (guint64) skipped, GST_MP3_TYPEFIND_TRY_SYNC);
  11.744 +        /* make sure we're not id3 tagged */
  11.745 +        head_data = gst_type_find_peek (tf, -128, 3);
  11.746 +        if (head_data && (memcmp (head_data, "TAG", 3) == 0)) {
  11.747 +          probability = 0;
  11.748 +        }
  11.749 +        g_assert (probability <= GST_TYPE_FIND_MAXIMUM);
  11.750 +
  11.751 +        *found_prob = probability;
  11.752 +        if (probability > 0)
  11.753 +          *found_layer = layer;
  11.754 +        return;
  11.755 +      }
  11.756 +    }
  11.757 +    data++;
  11.758 +    skipped++;
  11.759 +    size--;
  11.760 +  }
  11.761 +}
  11.762 +
  11.763 +static void
  11.764 +mp3_type_find (GstTypeFind * tf, gpointer unused)
  11.765 +{
  11.766 +  GstTypeFindProbability prob, mid_prob;
  11.767 +  guint8 *data;
  11.768 +  guint layer, mid_layer;
  11.769 +  guint64 length;
  11.770 +
  11.771 +  mp3_type_find_at_offset (tf, 0, &layer, &prob);
  11.772 +  length = gst_type_find_get_length (tf);
  11.773 +
  11.774 +  if (length == 0 || length == (guint64) - 1) {
  11.775 +    if (prob != 0)
  11.776 +      goto suggest;
  11.777 +    return;
  11.778 +  }
  11.779 +
  11.780 +  /* if we're pretty certain already, skip the additional check */
  11.781 +  if (prob >= GST_TYPE_FIND_LIKELY)
  11.782 +    goto suggest;
  11.783 +
  11.784 +  mp3_type_find_at_offset (tf, length / 2, &mid_layer, &mid_prob);
  11.785 +
  11.786 +  if (mid_prob > 0) {
  11.787 +    if (prob == 0) {
  11.788 +      GST_LOG ("detected audio/mpeg only in the middle (p=%u)", mid_prob);
  11.789 +      layer = mid_layer;
  11.790 +      prob = mid_prob;
  11.791 +      goto suggest;
  11.792 +    }
  11.793 +
  11.794 +    if (layer != mid_layer) {
  11.795 +      GST_WARNING ("audio/mpeg layer discrepancy: %u vs. %u", layer, mid_layer);
  11.796 +      return;                   /* FIXME: or should we just go with the one in the middle? */
  11.797 +    }
  11.798 +
  11.799 +    /* detected mpeg audio both in middle of the file and at the start */
  11.800 +    prob = (prob + mid_prob) / 2;
  11.801 +    goto suggest;
  11.802 +  }
  11.803 +
  11.804 +  /* let's see if there's a valid header right at the start */
  11.805 +  data = gst_type_find_peek (tf, 0, 4); /* use min. frame size? */
  11.806 +  if (data && mp3_type_frame_length_from_header (GST_READ_UINT32_BE (data),
  11.807 +          &layer, NULL, NULL, NULL, NULL, 0) != 0) {
  11.808 +    if (prob == 0)
  11.809 +      prob = GST_TYPE_FIND_POSSIBLE - 10;
  11.810 +    else
  11.811 +      prob = MAX (GST_TYPE_FIND_POSSIBLE - 10, prob + 10);
  11.812 +  }
  11.813 +
  11.814 +  if (prob > 0)
  11.815 +    goto suggest;
  11.816 +
  11.817 +  return;
  11.818 +
  11.819 +suggest:
  11.820 +  {
  11.821 +    GstCaps *caps;
  11.822 +
  11.823 +    g_assert (layer > 0);
  11.824 +
  11.825 +    caps = gst_caps_make_writable (MP3_CAPS);
  11.826 +    gst_structure_set (gst_caps_get_structure (caps, 0), "layer",
  11.827 +        G_TYPE_INT, layer, NULL);
  11.828 +    gst_type_find_suggest (tf, prob, caps);
  11.829 +    gst_caps_unref (caps);
  11.830 +    return;
  11.831 +  }
  11.832 +}
  11.833 +
  11.834 +/*** audio/x-musepack ***/
  11.835 +
  11.836 +static GstStaticCaps musepack_caps = GST_STATIC_CAPS ("audio/x-musepack");
  11.837 +
  11.838 +#define MUSEPACK_CAPS (gst_static_caps_get(&musepack_caps))
  11.839 +static void
  11.840 +musepack_type_find (GstTypeFind * tf, gpointer unused)
  11.841 +{
  11.842 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
  11.843 +
  11.844 +  if (data && memcmp (data, "MP+", 3) == 0) {
  11.845 +    if ((data[3] & 0x7f) == 7) {
  11.846 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MUSEPACK_CAPS);
  11.847 +    } else {
  11.848 +      gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY + 10, MUSEPACK_CAPS);
  11.849 +    }
  11.850 +  }
  11.851 +}
  11.852 +
  11.853 +/*** audio/x-ac3 ***/
  11.854 +static GstStaticCaps ac3_caps = GST_STATIC_CAPS ("audio/x-ac3");
  11.855 +
  11.856 +#define AC3_CAPS (gst_static_caps_get(&ac3_caps))
  11.857 +
  11.858 +static void
  11.859 +ac3_type_find (GstTypeFind * tf, gpointer unused)
  11.860 +{
  11.861 +  guint8 *data = gst_type_find_peek (tf, 0, 2);
  11.862 +
  11.863 +  if (data) {
  11.864 +    /* pretty lame method... */
  11.865 +    if (data[0] == 0x0b && data[1] == 0x77) {
  11.866 +      gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, AC3_CAPS);
  11.867 +      return;
  11.868 +    }
  11.869 +  }
  11.870 +}
  11.871 +
  11.872 +/*** wavpack ***/
  11.873 +
  11.874 +static GstStaticCaps wavpack_caps =
  11.875 +GST_STATIC_CAPS ("audio/x-wavpack, framed = (boolean) false");
  11.876 +
  11.877 +#define WAVPACK_CAPS (gst_static_caps_get(&wavpack_caps))
  11.878 +
  11.879 +static GstStaticCaps wavpack_correction_caps =
  11.880 +GST_STATIC_CAPS ("audio/x-wavpack-correction, framed = (boolean) false");
  11.881 +
  11.882 +#define WAVPACK_CORRECTION_CAPS (gst_static_caps_get(&wavpack_correction_caps))
  11.883 +
  11.884 +static void
  11.885 +wavpack_type_find (GstTypeFind * tf, gpointer unused)
  11.886 +{
  11.887 +  guint64 offset;
  11.888 +  guint32 blocksize;
  11.889 +  guint8 *data;
  11.890 +
  11.891 +  data = gst_type_find_peek (tf, 0, 32);
  11.892 +  if (!data)
  11.893 +    return;
  11.894 +
  11.895 +  if (data[0] != 'w' || data[1] != 'v' || data[2] != 'p' || data[3] != 'k')
  11.896 +    return;
  11.897 +
  11.898 +  /* Note: wavpack blocks can be fairly large (easily 60-110k), possibly
  11.899 +   * larger than the max. limits imposed by certain typefinding elements
  11.900 +   * like id3demux or apedemux, so typefinding is most likely only going to
  11.901 +   * work in pull-mode */
  11.902 +  blocksize = GST_READ_UINT32_LE (data + 4);
  11.903 +  GST_LOG ("wavpack header, blocksize=0x%04x", blocksize);
  11.904 +  offset = 32;
  11.905 +  while (offset < 32 + blocksize) {
  11.906 +    guint32 sublen;
  11.907 +
  11.908 +    /* get chunk header */
  11.909 +    GST_LOG ("peeking at chunk at offset 0x%04x", (guint) offset);
  11.910 +    data = gst_type_find_peek (tf, offset, 4);
  11.911 +    if (data == NULL)
  11.912 +      break;
  11.913 +    sublen = ((guint32) data[1]) << 1;
  11.914 +    if (data[0] & 0x80) {
  11.915 +      sublen |= (((guint32) data[2]) << 9) | (((guint32) data[3]) << 17);
  11.916 +      sublen += 1 + 3;          /* id + length */
  11.917 +    } else {
  11.918 +      sublen += 1 + 1;          /* id + length */
  11.919 +    }
  11.920 +    if (sublen > blocksize - offset + 32) {
  11.921 +      GST_LOG ("chunk length too big (%u > %" G_GUINT64_FORMAT ")", sublen,
  11.922 +          blocksize - offset);
  11.923 +      break;
  11.924 +    }
  11.925 +    if ((data[0] & 0x20) == 0) {
  11.926 +      switch (data[0] & 0x0f) {
  11.927 +        case 0xa:              /* ID_WV_BITSTREAM  */
  11.928 +        case 0xc:              /* ID_WVX_BITSTREAM */
  11.929 +          gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, WAVPACK_CAPS);
  11.930 +          return;
  11.931 +        case 0xb:              /* ID_WVC_BITSTREAM */
  11.932 +          gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY,
  11.933 +              WAVPACK_CORRECTION_CAPS);
  11.934 +          return;
  11.935 +        default:
  11.936 +          break;
  11.937 +      }
  11.938 +    }
  11.939 +    offset += sublen;
  11.940 +  }
  11.941 +}
  11.942 +
  11.943 +/*** multipart/x-mixed-replace mimestream ***/
  11.944 +
  11.945 +static GstStaticCaps multipart_caps =
  11.946 +GST_STATIC_CAPS ("multipart/x-mixed-replace");
  11.947 +#define MULTIPART_CAPS gst_static_caps_get(&multipart_caps)
  11.948 +
  11.949 +/* multipart/x-mixed replace is: 
  11.950 + *   <maybe some whitespace>--<some ascii chars>[\r]\n
  11.951 + *   <more ascii chars>[\r]\nContent-type:<more ascii>[\r]\n */
  11.952 +static void
  11.953 +multipart_type_find (GstTypeFind * tf, gpointer unused)
  11.954 +{
  11.955 +  guint8 *data;
  11.956 +  guint8 *x;
  11.957 +
  11.958 +#define MULTIPART_MAX_BOUNDARY_OFFSET 16
  11.959 +  data = gst_type_find_peek (tf, 0, MULTIPART_MAX_BOUNDARY_OFFSET);
  11.960 +  if (!data)
  11.961 +    return;
  11.962 +
  11.963 +  for (x = data;
  11.964 +      x - data < MULTIPART_MAX_BOUNDARY_OFFSET - 2 && g_ascii_isspace (*x);
  11.965 +      x++);
  11.966 +  if (x[0] != '-' || x[1] != '-')
  11.967 +    return;
  11.968 +
  11.969 +  /* Could be okay, peek what should be enough for a complete header */
  11.970 +#define MULTIPART_MAX_HEADER_SIZE 256
  11.971 +  data = gst_type_find_peek (tf, 0, MULTIPART_MAX_HEADER_SIZE);
  11.972 +  if (!data)
  11.973 +    return;
  11.974 +
  11.975 +  for (x = data; x - data < MULTIPART_MAX_HEADER_SIZE - 14; x++) {
  11.976 +    if (!isascii (*x)) {
  11.977 +      return;
  11.978 +    }
  11.979 +    if (*x == '\n' &&
  11.980 +        !g_ascii_strncasecmp ("content-type:", (gchar *) x + 1, 13)) {
  11.981 +      GstCaps *caps = gst_caps_copy (MULTIPART_CAPS);
  11.982 +
  11.983 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, caps);
  11.984 +      gst_caps_unref (caps);
  11.985 +      return;
  11.986 +    }
  11.987 +  }
  11.988 +}
  11.989 +
  11.990 +/*** video/mpeg systemstream ***/
  11.991 +static GstStaticCaps mpeg_sys_caps = GST_STATIC_CAPS ("video/mpeg, "
  11.992 +    "systemstream = (boolean) true, mpegversion = (int) [ 1, 2 ]");
  11.993 +
  11.994 +#define MPEG_SYS_CAPS gst_static_caps_get(&mpeg_sys_caps)
  11.995 +#define IS_MPEG_HEADER(data)            ((((guint8 *)(data))[0] == 0x00) &&  \
  11.996 +                                         (((guint8 *)(data))[1] == 0x00) &&  \
  11.997 +                                         (((guint8 *)(data))[2] == 0x01))
  11.998 +
  11.999 +#define IS_MPEG_PACK_HEADER(data)       (IS_MPEG_HEADER (data) &&            \
 11.1000 +                                         (((guint8 *)(data))[3] == 0xBA))
 11.1001 +
 11.1002 +#define IS_MPEG_SYSTEM_HEADER(data)     (IS_MPEG_HEADER (data) &&            \
 11.1003 +                                         (((guint8 *)(data))[3] == 0xBB))
 11.1004 +#define IS_MPEG_PACKET_HEADER(data)     (IS_MPEG_HEADER (data) &&            \
 11.1005 +                                         ((((guint8 *)(data))[3] & 0x80) == 0x80))
 11.1006 +
 11.1007 +#define IS_MPEG_PES_HEADER(data)        (IS_MPEG_HEADER (data) &&            \
 11.1008 +                                         ((((guint8 *)(data))[3] == 0xE0) || \
 11.1009 +                                          (((guint8 *)(data))[3] == 0xC0) || \
 11.1010 +                                          (((guint8 *)(data))[3] == 0xBD)))
 11.1011 +
 11.1012 +static void
 11.1013 +mpeg2_sys_type_find (GstTypeFind * tf, gpointer unused)
 11.1014 +{
 11.1015 +  guint8 *data = gst_type_find_peek (tf, 0, 5);
 11.1016 +  gint mpegversion;
 11.1017 +
 11.1018 +  if (data && IS_MPEG_PACK_HEADER (data)) {
 11.1019 +    if ((data[4] & 0xC0) == 0x40) {
 11.1020 +      /* type 2 */
 11.1021 +      mpegversion = 2;
 11.1022 +      goto suggest;
 11.1023 +    } else if ((data[4] & 0xF0) == 0x20) {
 11.1024 +      mpegversion = 1;
 11.1025 +      goto suggest;
 11.1026 +    }
 11.1027 +  } else if (data && IS_MPEG_PES_HEADER (data)) {
 11.1028 +    /* PES stream */
 11.1029 +    mpegversion = 2;
 11.1030 +    goto suggest;
 11.1031 +  }
 11.1032 +
 11.1033 +  return;
 11.1034 +suggest:
 11.1035 +  {
 11.1036 +    GstCaps *caps = gst_caps_copy (MPEG_SYS_CAPS);
 11.1037 +
 11.1038 +    gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
 11.1039 +        G_TYPE_INT, mpegversion, NULL);
 11.1040 +    gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, caps);
 11.1041 +    gst_caps_unref (caps);
 11.1042 +  }
 11.1043 +};
 11.1044 +
 11.1045 +/* ATTENTION: ugly return value:
 11.1046 + * 0 -  invalid data
 11.1047 + * 1 - not enough data
 11.1048 + * anything else - size until next package
 11.1049 + */
 11.1050 +static guint
 11.1051 +mpeg1_parse_header (GstTypeFind * tf, guint64 offset)
 11.1052 +{
 11.1053 +  guint8 *data = gst_type_find_peek (tf, offset, 4);
 11.1054 +  guint size;
 11.1055 +
 11.1056 +  if (!data) {
 11.1057 +    GST_LOG ("couldn't get MPEG header bytes");
 11.1058 +    return 1;
 11.1059 +  }
 11.1060 +
 11.1061 +  if (data[0] != 0 || data[1] != 0 || data[2] != 1) {
 11.1062 +    GST_LOG ("no sync");
 11.1063 +    return 0;
 11.1064 +  }
 11.1065 +  offset += 4;
 11.1066 +
 11.1067 +  GST_LOG ("sync %02x", data[3]);
 11.1068 +
 11.1069 +  switch (data[3]) {
 11.1070 +    case 0xBA:                 /* pack header */
 11.1071 +      data = gst_type_find_peek (tf, offset, 8);
 11.1072 +      if (!data) {
 11.1073 +        GST_LOG ("couldn't get MPEG pack header bytes");
 11.1074 +        return 1;
 11.1075 +      }
 11.1076 +      size = 12;
 11.1077 +      /* check marker bits */
 11.1078 +      if ((data[0] & 0xF1) != 0x21 ||
 11.1079 +          (data[2] & 0x01) != 0x01 ||
 11.1080 +          (data[4] & 0x01) != 0x01 ||
 11.1081 +          (data[5] & 0x80) != 0x80 || (data[7] & 0x01) != 0x01) {
 11.1082 +        GST_LOG ("wrong marker bits");
 11.1083 +        return 0;
 11.1084 +      }
 11.1085 +      break;
 11.1086 +
 11.1087 +    case 0xB9:                 /* ISO end code */
 11.1088 +      size = 4;
 11.1089 +      break;
 11.1090 +
 11.1091 +    case 0xBB:                 /* system header */
 11.1092 +      data = gst_type_find_peek (tf, offset, 2);
 11.1093 +      if (!data) {
 11.1094 +        GST_LOG ("couldn't get MPEG pack header bytes");
 11.1095 +        return 1;
 11.1096 +      }
 11.1097 +      size = GST_READ_UINT16_BE (data) + 6;
 11.1098 +      offset += 2;
 11.1099 +      data = gst_type_find_peek (tf, offset, size - 6);
 11.1100 +      if (!data) {
 11.1101 +        GST_LOG ("couldn't get MPEG pack header bytes");
 11.1102 +        return 1;
 11.1103 +      }
 11.1104 +      /* check marker bits */
 11.1105 +      if ((data[0] & 0x80) != 0x80 ||
 11.1106 +          (data[2] & 0x01) != 0x01 || (data[4] & 0x20) != 0x20) {
 11.1107 +        GST_LOG ("wrong marker bits");
 11.1108 +        return 0;
 11.1109 +      }
 11.1110 +      /* check stream marker bits */
 11.1111 +      for (offset = 6; offset < (size - 6); offset += 3) {
 11.1112 +        if (data[offset] <= 0xBB || (data[offset + 1] & 0xC0) != 0xC0) {
 11.1113 +          GST_LOG ("wrong marker bits");
 11.1114 +          return 0;
 11.1115 +        }
 11.1116 +      }
 11.1117 +      break;
 11.1118 +
 11.1119 +    default:
 11.1120 +      if (data[3] < 0xB9)
 11.1121 +        return 0;
 11.1122 +      data = gst_type_find_peek (tf, offset, 2);
 11.1123 +      if (!data) {
 11.1124 +        GST_LOG ("couldn't get MPEG pack header bytes");
 11.1125 +        return 1;
 11.1126 +      }
 11.1127 +      size = GST_READ_UINT16_BE (data) + 6;
 11.1128 +      /* FIXME: we could check PTS/DTS marker bits here... (bit overkill) */
 11.1129 +      break;
 11.1130 +  }
 11.1131 +
 11.1132 +  return size;
 11.1133 +}
 11.1134 +
 11.1135 +/* calculation of possibility to identify random data as mpeg systemstream:
 11.1136 + * bits that must match in header detection:            32 (or more)
 11.1137 + * chance that random data is identifed:                1/2^32
 11.1138 + * chance that GST_MPEG_TYPEFIND_TRY_HEADERS headers are identified:
 11.1139 + *                                      1/2^(32*GST_MPEG_TYPEFIND_TRY_HEADERS)
 11.1140 + * chance that this happens in GST_MPEG_TYPEFIND_TRY_SYNC bytes:
 11.1141 + *                                      1-(1+1/2^(32*GST_MPEG_TYPEFIND_TRY_HEADERS)^GST_MPEG_TYPEFIND_TRY_SYNC)
 11.1142 + * for current values:
 11.1143 + *                                      1-(1+1/2^(32*4)^101024)
 11.1144 + *                                    = <some_number>
 11.1145 + */
 11.1146 +#define GST_MPEG_TYPEFIND_TRY_HEADERS 4
 11.1147 +#define GST_MPEG_TYPEFIND_TRY_SYNC (100 * 1024) /* 100kB */
 11.1148 +#define GST_MPEG_TYPEFIND_SYNC_SIZE 2048
 11.1149 +static void
 11.1150 +mpeg1_sys_type_find (GstTypeFind * tf, gpointer unused)
 11.1151 +{
 11.1152 +  guint8 *data = NULL;
 11.1153 +  guint size = 0;
 11.1154 +  guint64 skipped = 0;
 11.1155 +  GstCaps *caps;
 11.1156 +
 11.1157 +  while (skipped < GST_MPEG_TYPEFIND_TRY_SYNC) {
 11.1158 +    if (size < 4) {
 11.1159 +      data = gst_type_find_peek (tf, skipped, GST_MPEG_TYPEFIND_SYNC_SIZE);
 11.1160 +      if (!data)
 11.1161 +        break;
 11.1162 +      size = GST_MPEG_TYPEFIND_SYNC_SIZE;
 11.1163 +    }
 11.1164 +    if (IS_MPEG_PACK_HEADER (data)) {
 11.1165 +      /* found packet start code */
 11.1166 +      guint found = 0;
 11.1167 +      guint packet_size = 0;
 11.1168 +      guint64 offset = skipped;
 11.1169 +
 11.1170 +      while (found < GST_MPEG_TYPEFIND_TRY_HEADERS) {
 11.1171 +        packet_size = mpeg1_parse_header (tf, offset);
 11.1172 +        if (packet_size <= 1)
 11.1173 +          break;
 11.1174 +        offset += packet_size;
 11.1175 +        found++;
 11.1176 +      }
 11.1177 +      g_assert (found <= GST_MPEG_TYPEFIND_TRY_HEADERS);
 11.1178 +      if (found == GST_MPEG_TYPEFIND_TRY_HEADERS || packet_size == 1) {
 11.1179 +        GST_LOG ("suggesting mpeg1 system steeam");
 11.1180 +        caps = gst_caps_copy (MPEG_SYS_CAPS);
 11.1181 +        gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
 11.1182 +            G_TYPE_INT, 1, NULL);
 11.1183 +        gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps);
 11.1184 +        gst_caps_unref (caps);
 11.1185 +        return;
 11.1186 +      }
 11.1187 +    }
 11.1188 +    data++;
 11.1189 +    skipped++;
 11.1190 +    size--;
 11.1191 +  }
 11.1192 +}
 11.1193 +
 11.1194 +/** video/mpegts Transport Stream **/
 11.1195 +static GstStaticCaps mpegts_caps = GST_STATIC_CAPS ("video/mpegts, "
 11.1196 +    "systemstream = (boolean) true, packetsize = (int) [ 188, 208 ]");
 11.1197 +#define MPEGTS_CAPS gst_static_caps_get(&mpegts_caps)
 11.1198 +
 11.1199 +#define GST_MPEGTS_TYPEFIND_MIN_HEADERS 4
 11.1200 +#define GST_MPEGTS_TYPEFIND_MAX_HEADERS 10
 11.1201 +#define GST_MPEGTS_MAX_PACKET_SIZE 204
 11.1202 +#define GST_MPEGTS_TYPEFIND_SYNC_SIZE \
 11.1203 +            (GST_MPEGTS_TYPEFIND_MIN_HEADERS * GST_MPEGTS_MAX_PACKET_SIZE)
 11.1204 +#define GST_MPEGTS_TYPEFIND_MAX_SYNC \
 11.1205 +            (GST_MPEGTS_TYPEFIND_MAX_HEADERS * GST_MPEGTS_MAX_PACKET_SIZE)
 11.1206 +
 11.1207 +#define MPEGTS_HDR_SIZE 4
 11.1208 +#define IS_MPEGTS_HEADER(data) (((data)[0] == 0x47) && \
 11.1209 +                                (((data)[1] & 0x80) == 0x00) && \
 11.1210 +                                (((data)[3] & 0x10) == 0x10))
 11.1211 +
 11.1212 +/* Helper function to search ahead at intervals of packet_size for mpegts
 11.1213 + * headers */
 11.1214 +gint
 11.1215 +mpeg_ts_probe_headers (GstTypeFind * tf, guint64 offset, gint packet_size)
 11.1216 +{
 11.1217 +  /* We always enter this function having found at least one header already */
 11.1218 +  gint found = 1;
 11.1219 +  guint8 *data = NULL;
 11.1220 +
 11.1221 +  while (found < GST_MPEGTS_TYPEFIND_MAX_HEADERS) {
 11.1222 +    offset += packet_size;
 11.1223 +
 11.1224 +    data = gst_type_find_peek (tf, offset, MPEGTS_HDR_SIZE);
 11.1225 +    if (data == NULL || !IS_MPEGTS_HEADER (data))
 11.1226 +      return found;
 11.1227 +
 11.1228 +    found++;
 11.1229 +  }
 11.1230 +
 11.1231 +  return found;
 11.1232 +}
 11.1233 +
 11.1234 +/* Try and detect at least 4 packets in at most 10 packets worth of
 11.1235 + * data. Need to try several possible packet sizes */
 11.1236 +static void
 11.1237 +mpeg_ts_type_find (GstTypeFind * tf, gpointer unused)
 11.1238 +{
 11.1239 +  /* TS packet sizes to test: normal, DVHS packet size and 
 11.1240 +   * FEC with 16 or 20 byte codes packet size. */
 11.1241 +  const gint pack_sizes[] = { 188, 192, 204, 208 };
 11.1242 +  const gint n_pack_sizes = sizeof (pack_sizes) / sizeof (gint);
 11.1243 +
 11.1244 +  guint8 *data = NULL;
 11.1245 +  guint size = 0;
 11.1246 +  guint64 skipped = 0;
 11.1247 +
 11.1248 +  while (skipped < GST_MPEGTS_TYPEFIND_MAX_SYNC) {
 11.1249 +    if (size < MPEGTS_HDR_SIZE) {
 11.1250 +      data = gst_type_find_peek (tf, skipped, GST_MPEGTS_TYPEFIND_SYNC_SIZE);
 11.1251 +      if (!data)
 11.1252 +        break;
 11.1253 +      size = GST_MPEGTS_TYPEFIND_SYNC_SIZE;
 11.1254 +    }
 11.1255 +
 11.1256 +    /* Have at least MPEGTS_HDR_SIZE bytes at this point */
 11.1257 +    if (IS_MPEGTS_HEADER (data)) {
 11.1258 +      gint p;
 11.1259 +
 11.1260 +      for (p = 0; p < n_pack_sizes; p++) {
 11.1261 +        gint found;
 11.1262 +
 11.1263 +        /* Probe ahead at size pack_sizes[p] */
 11.1264 +        found = mpeg_ts_probe_headers (tf, skipped, pack_sizes[p]);
 11.1265 +        if (found >= GST_MPEGTS_TYPEFIND_MIN_HEADERS) {
 11.1266 +          gint probability;
 11.1267 +          GstCaps *caps = gst_caps_copy (MPEGTS_CAPS);
 11.1268 +
 11.1269 +          gst_structure_set (gst_caps_get_structure (caps, 0), "packetsize",
 11.1270 +              G_TYPE_INT, pack_sizes[p], NULL);
 11.1271 +
 11.1272 +          /* found at least 4 headers. 10 headers = MAXIMUM probability. 
 11.1273 +           * Arbitrarily, I assigned 10% probability for each header we
 11.1274 +           * found, 40% -> 100% */
 11.1275 +
 11.1276 +          probability = 10 * MIN (found, 10);
 11.1277 +
 11.1278 +          gst_type_find_suggest (tf, probability, caps);
 11.1279 +          gst_caps_unref (caps);
 11.1280 +          return;
 11.1281 +        }
 11.1282 +      }
 11.1283 +    }
 11.1284 +    data++;
 11.1285 +    skipped++;
 11.1286 +    size--;
 11.1287 +  }
 11.1288 +}
 11.1289 +
 11.1290 +/*** video/mpeg MPEG-4 elementary video stream ***/
 11.1291 +
 11.1292 +static GstStaticCaps mpeg4_video_caps = GST_STATIC_CAPS ("video/mpeg, "
 11.1293 +    "systemstream = (boolean) false, mpegversion = 4");
 11.1294 +#define MPEG4_VIDEO_CAPS gst_static_caps_get(&mpeg4_video_caps)
 11.1295 +static void
 11.1296 +mpeg4_video_type_find (GstTypeFind * tf, gpointer unused)
 11.1297 +{
 11.1298 +  /* Header consists of: a series of start codes (00 00 01 xx), some with 
 11.1299 +   * associated data.
 11.1300 +   * Optionally, we start with a visual_object_sequence_start_code, followed by
 11.1301 +   * (optionally) visual_object_start_code), then the mandatory 
 11.1302 +   * video_object_start_code and video_object_layer_start_code)
 11.1303 +   */
 11.1304 +  guint8 *data = NULL;
 11.1305 +  int offset = 0;
 11.1306 +  gboolean seen_vos = FALSE;
 11.1307 +
 11.1308 +  while (TRUE) {
 11.1309 +    data = gst_type_find_peek (tf, offset, 4);
 11.1310 +    if (data && data[0] == 0 && data[1] == 0 && data[2] == 1) {
 11.1311 +      int sc = data[3];
 11.1312 +
 11.1313 +      if (sc == 0xB0)           /* visual_object_sequence_start_code */
 11.1314 +        offset += 5;
 11.1315 +      else if (sc == 0xB5)      /* visual_object_start_code */
 11.1316 +        offset += 5;
 11.1317 +      else if (sc >= 0x00 && sc <= 0x1F) {      /* video_object_start_code */
 11.1318 +        offset += 4;
 11.1319 +        seen_vos = TRUE;
 11.1320 +      } else if (sc >= 0x20 && sc <= 0x2F) {    /* video_object_layer_start_code */
 11.1321 +        if (seen_vos) {
 11.1322 +          GstCaps *caps = gst_caps_copy (MPEG4_VIDEO_CAPS);
 11.1323 +
 11.1324 +          gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps);
 11.1325 +          gst_caps_unref (caps);
 11.1326 +          return;
 11.1327 +        }
 11.1328 +      } else
 11.1329 +        return;
 11.1330 +    } else
 11.1331 +      return;
 11.1332 +  }
 11.1333 +}
 11.1334 +
 11.1335 +/*** video/mpeg video stream ***/
 11.1336 +
 11.1337 +static GstStaticCaps mpeg_video_caps = GST_STATIC_CAPS ("video/mpeg, "
 11.1338 +    "systemstream = (boolean) false");
 11.1339 +#define MPEG_VIDEO_CAPS gst_static_caps_get(&mpeg_video_caps)
 11.1340 +static void
 11.1341 +mpeg_video_type_find (GstTypeFind * tf, gpointer unused)
 11.1342 +{
 11.1343 +  static const guint8 sequence_header[] = { 0x00, 0x00, 0x01, 0xb3 };
 11.1344 +  guint8 *data = NULL;
 11.1345 +
 11.1346 +  data = gst_type_find_peek (tf, 0, 8);
 11.1347 +
 11.1348 +  if (data && memcmp (data, sequence_header, 4) == 0) {
 11.1349 +    GstCaps *caps = gst_caps_copy (MPEG_VIDEO_CAPS);
 11.1350 +
 11.1351 +    gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
 11.1352 +        G_TYPE_INT, 1, NULL);
 11.1353 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps);
 11.1354 +    gst_caps_unref (caps);
 11.1355 +  }
 11.1356 +}
 11.1357 +
 11.1358 +/*
 11.1359 + * Idea is the same as MPEG system stream typefinding: We check each
 11.1360 + * byte of the stream to see if - from that point on - the stream
 11.1361 + * matches a predefined set of marker bits as defined in the MPEG
 11.1362 + * video specs.
 11.1363 + *
 11.1364 + * I'm sure someone will do a chance calculation here too.
 11.1365 + */
 11.1366 +
 11.1367 +#define GST_MPEGVID_TYPEFIND_TRY_PICTURES 6
 11.1368 +#define GST_MPEGVID_TYPEFIND_TRY_SYNC (100 * 1024)      /* 100 kB */
 11.1369 +#define GST_MPEGVID_TYPEFIND_SYNC_SIZE 2048
 11.1370 +
 11.1371 +static void
 11.1372 +mpeg_video_stream_type_find (GstTypeFind * tf, gpointer unused)
 11.1373 +{
 11.1374 +  gint size = 0, found = 0;
 11.1375 +  guint64 skipped = 0;
 11.1376 +  guint8 *data = NULL;
 11.1377 +
 11.1378 +  while (1) {
 11.1379 +    if (found >= GST_MPEGVID_TYPEFIND_TRY_PICTURES) {
 11.1380 +      GstCaps *caps = gst_caps_copy (MPEG_VIDEO_CAPS);
 11.1381 +
 11.1382 +      gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
 11.1383 +          G_TYPE_INT, 1, NULL);
 11.1384 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 2, caps);
 11.1385 +      gst_caps_unref (caps);
 11.1386 +      return;
 11.1387 +    }
 11.1388 +
 11.1389 +    if (skipped > GST_MPEGVID_TYPEFIND_TRY_SYNC)
 11.1390 +      break;
 11.1391 +
 11.1392 +    if (size < 5) {
 11.1393 +      data = gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE);
 11.1394 +      if (!data)
 11.1395 +        break;
 11.1396 +      size = GST_MPEGVID_TYPEFIND_SYNC_SIZE;
 11.1397 +    }
 11.1398 +
 11.1399 +    /* are we a sequence (0xB3) or GOP (0xB8) header? */
 11.1400 +    if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x1 &&
 11.1401 +        (data[3] == 0xB3 || data[3] == 0xB8)) {
 11.1402 +      size -= 8;
 11.1403 +      data += 8;
 11.1404 +      skipped += 8;
 11.1405 +      if (data[3] == 0xB3)
 11.1406 +        continue;
 11.1407 +      else if (size < 4) {
 11.1408 +        data = gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE);
 11.1409 +        size = GST_MPEGVID_TYPEFIND_SYNC_SIZE;
 11.1410 +        if (!data)
 11.1411 +          break;
 11.1412 +      }
 11.1413 +      /* else, we should now see an image */
 11.1414 +    }
 11.1415 +
 11.1416 +    /* image header (and, when found, slice header) */
 11.1417 +    if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x1 && data[4] == 0x0) {
 11.1418 +      size -= 8;
 11.1419 +      data += 8;
 11.1420 +      skipped += 8;
 11.1421 +      if (size < 5) {
 11.1422 +        data = gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE);
 11.1423 +        size = GST_MPEGVID_TYPEFIND_SYNC_SIZE;
 11.1424 +        if (!data)
 11.1425 +          break;
 11.1426 +      }
 11.1427 +      if ((data[0] == 0x0 && data[1] == 0x0 &&
 11.1428 +              data[2] == 0x1 && data[3] == 0x1) ||
 11.1429 +          (data[1] == 0x0 && data[2] == 0x0 &&
 11.1430 +              data[3] == 0x1 && data[4] == 0x1)) {
 11.1431 +        size -= 4;
 11.1432 +        data += 4;
 11.1433 +        skipped += 4;
 11.1434 +        found += 1;
 11.1435 +        continue;
 11.1436 +      }
 11.1437 +    }
 11.1438 +
 11.1439 +    size--;
 11.1440 +    data++;
 11.1441 +    skipped++;
 11.1442 +  }
 11.1443 +}
 11.1444 +
 11.1445 +/*** audio/x-aiff ***/
 11.1446 +
 11.1447 +static GstStaticCaps aiff_caps = GST_STATIC_CAPS ("audio/x-aiff");
 11.1448 +
 11.1449 +#define AIFF_CAPS gst_static_caps_get(&aiff_caps)
 11.1450 +static void
 11.1451 +aiff_type_find (GstTypeFind * tf, gpointer unused)
 11.1452 +{
 11.1453 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.1454 +
 11.1455 +  if (data && memcmp (data, "FORM", 4) == 0) {
 11.1456 +    data += 8;
 11.1457 +    if (memcmp (data, "AIFF", 4) == 0 || memcmp (data, "AIFC", 4) == 0)
 11.1458 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, AIFF_CAPS);
 11.1459 +  }
 11.1460 +}
 11.1461 +
 11.1462 +/*** audio/x-aiff ***/
 11.1463 +
 11.1464 +static GstStaticCaps svx_caps = GST_STATIC_CAPS ("audio/x-svx");
 11.1465 +
 11.1466 +#define SVX_CAPS gst_static_caps_get(&svx_caps)
 11.1467 +static void
 11.1468 +svx_type_find (GstTypeFind * tf, gpointer unused)
 11.1469 +{
 11.1470 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.1471 +
 11.1472 +  if (data && memcmp (data, "FORM", 4) == 0) {
 11.1473 +    data += 8;
 11.1474 +    if (memcmp (data, "8SVX", 4) == 0 || memcmp (data, "16SV", 4) == 0)
 11.1475 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SVX_CAPS);
 11.1476 +  }
 11.1477 +}
 11.1478 +
 11.1479 +/*** audio/x-shorten ***/
 11.1480 +
 11.1481 +static GstStaticCaps shn_caps = GST_STATIC_CAPS ("audio/x-shorten");
 11.1482 +
 11.1483 +#define SHN_CAPS gst_static_caps_get(&shn_caps)
 11.1484 +static void
 11.1485 +shn_type_find (GstTypeFind * tf, gpointer unused)
 11.1486 +{
 11.1487 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.1488 +
 11.1489 +  if (data && memcmp (data, "ajkg", 4) == 0) {
 11.1490 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SHN_CAPS);
 11.1491 +  }
 11.1492 +  data = gst_type_find_peek (tf, -8, 8);
 11.1493 +  if (data && memcmp (data, "SHNAMPSK", 8) == 0) {
 11.1494 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SHN_CAPS);
 11.1495 +  }
 11.1496 +}
 11.1497 +
 11.1498 +/*** application/x-ape ***/
 11.1499 +
 11.1500 +static GstStaticCaps ape_caps = GST_STATIC_CAPS ("application/x-ape");
 11.1501 +
 11.1502 +#define APE_CAPS gst_static_caps_get(&ape_caps)
 11.1503 +static void
 11.1504 +ape_type_find (GstTypeFind * tf, gpointer unused)
 11.1505 +{
 11.1506 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.1507 +
 11.1508 +  if (data && memcmp (data, "MAC ", 4) == 0) {
 11.1509 +    gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY + 10, APE_CAPS);
 11.1510 +  }
 11.1511 +}
 11.1512 +
 11.1513 +/*** ISO FORMATS ***/
 11.1514 +
 11.1515 +/*** audio/x-m4a ***/
 11.1516 +
 11.1517 +static GstStaticCaps m4a_caps = GST_STATIC_CAPS ("audio/x-m4a");
 11.1518 +
 11.1519 +#define M4A_CAPS (gst_static_caps_get(&m4a_caps))
 11.1520 +static void
 11.1521 +m4a_type_find (GstTypeFind * tf, gpointer unused)
 11.1522 +{
 11.1523 +  guint8 *data = gst_type_find_peek (tf, 4, 8);
 11.1524 +
 11.1525 +  if (data &&
 11.1526 +      (memcmp (data, "ftypM4A ", 8) == 0 ||
 11.1527 +          memcmp (data, "ftypmp42", 8) == 0)) {
 11.1528 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, M4A_CAPS);
 11.1529 +  }
 11.1530 +}
 11.1531 +
 11.1532 +/*** application/x-3gp ***/
 11.1533 +
 11.1534 +/* The Q is there because variables can't start with a number. */
 11.1535 +
 11.1536 +
 11.1537 +static GstStaticCaps q3gp_caps = GST_STATIC_CAPS ("application/x-3gp");
 11.1538 +
 11.1539 +#define Q3GP_CAPS (gst_static_caps_get(&q3gp_caps))
 11.1540 +static void
 11.1541 +q3gp_type_find (GstTypeFind * tf, gpointer unused)
 11.1542 +{
 11.1543 +
 11.1544 +  guint32 ftyp_size = 0;
 11.1545 +  gint offset = 0;
 11.1546 +  guint8 *data = NULL;
 11.1547 +
 11.1548 +  if ((data = gst_type_find_peek (tf, 0, 12)) == NULL) {
 11.1549 +    return;
 11.1550 +  }
 11.1551 +
 11.1552 +  data += 4;
 11.1553 +  if (memcmp (data, "ftyp", 4) != 0) {
 11.1554 +    return;
 11.1555 +  }
 11.1556 +
 11.1557 +  /* check major brand */
 11.1558 +  data += 4;
 11.1559 +  if (memcmp (data, "3gp", 3) == 0 ||
 11.1560 +      memcmp (data, "3gr", 3) == 0 ||
 11.1561 +      memcmp (data, "3gs", 3) == 0 || memcmp (data, "3gg", 3) == 0) {
 11.1562 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, Q3GP_CAPS);
 11.1563 +    return;
 11.1564 +  }
 11.1565 +
 11.1566 +  /* check compatible brands */
 11.1567 +  if ((data = gst_type_find_peek (tf, 0, 4)) != NULL) {
 11.1568 +    ftyp_size = GST_READ_UINT32_BE (data);
 11.1569 +  }
 11.1570 +  for (offset = 16; offset < ftyp_size; offset += 4) {
 11.1571 +    if ((data = gst_type_find_peek (tf, offset, 3)) == NULL) {
 11.1572 +      break;
 11.1573 +    }
 11.1574 +    if (memcmp (data, "3gp", 3) == 0 ||
 11.1575 +        memcmp (data, "3gr", 3) == 0 ||
 11.1576 +        memcmp (data, "3gs", 3) == 0 || memcmp (data, "3gg", 3) == 0) {
 11.1577 +      gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, Q3GP_CAPS);
 11.1578 +      break;
 11.1579 +    }
 11.1580 +  }
 11.1581 +
 11.1582 +  return;
 11.1583 +
 11.1584 +}
 11.1585 +
 11.1586 +/*** video/quicktime ***/
 11.1587 +
 11.1588 +static GstStaticCaps qt_caps = GST_STATIC_CAPS ("video/quicktime");
 11.1589 +
 11.1590 +#define QT_CAPS gst_static_caps_get(&qt_caps)
 11.1591 +#define STRNCMP(x,y,z) (strncmp ((char*)(x), (char*)(y), z))
 11.1592 +
 11.1593 +static void
 11.1594 +qt_type_find (GstTypeFind * tf, gpointer unused)
 11.1595 +{
 11.1596 +  guint8 *data;
 11.1597 +  guint tip = 0;
 11.1598 +  guint64 offset = 0;
 11.1599 +  guint64 size;
 11.1600 +
 11.1601 +  while ((data = gst_type_find_peek (tf, offset, 8)) != NULL) {
 11.1602 +    /* box/atom types that are in common with ISO base media file format */
 11.1603 +    if (STRNCMP (&data[4], "moov", 4) == 0 ||
 11.1604 +        STRNCMP (&data[4], "mdat", 4) == 0 ||
 11.1605 +        STRNCMP (&data[4], "ftyp", 4) == 0 ||
 11.1606 +        STRNCMP (&data[4], "free", 4) == 0 ||
 11.1607 +        STRNCMP (&data[4], "uuid", 4) == 0 ||
 11.1608 +        STRNCMP (&data[4], "skip", 4) == 0) {
 11.1609 +      if (tip == 0) {
 11.1610 +        tip = GST_TYPE_FIND_LIKELY;
 11.1611 +      } else {
 11.1612 +        tip = GST_TYPE_FIND_NEARLY_CERTAIN;
 11.1613 +      }
 11.1614 +    }
 11.1615 +    /* other box/atom types, apparently quicktime specific */
 11.1616 +    else if (STRNCMP (&data[4], "pnot", 4) == 0 ||
 11.1617 +        STRNCMP (&data[4], "PICT", 4) == 0 ||
 11.1618 +        STRNCMP (&data[4], "wide", 4) == 0 ||
 11.1619 +        STRNCMP (&data[4], "prfl", 4) == 0) {
 11.1620 +      tip = GST_TYPE_FIND_MAXIMUM;
 11.1621 +      break;
 11.1622 +    } else {
 11.1623 +      tip = 0;
 11.1624 +      break;
 11.1625 +    }
 11.1626 +    size = GST_READ_UINT32_BE (data);
 11.1627 +    if (size == 1) {
 11.1628 +      guint8 *sizedata;
 11.1629 +
 11.1630 +      sizedata = gst_type_find_peek (tf, offset + 8, 8);
 11.1631 +      if (sizedata == NULL)
 11.1632 +        break;
 11.1633 +
 11.1634 +      size = GST_READ_UINT64_BE (sizedata);
 11.1635 +    } else {
 11.1636 +      if (size < 8)
 11.1637 +        break;
 11.1638 +    }
 11.1639 +    offset += size;
 11.1640 +  }
 11.1641 +  if (tip > 0) {
 11.1642 +    gst_type_find_suggest (tf, tip, QT_CAPS);
 11.1643 +  }
 11.1644 +};
 11.1645 +
 11.1646 +
 11.1647 +/*** image/x-quicktime ***/
 11.1648 +
 11.1649 +static GstStaticCaps qtif_caps = GST_STATIC_CAPS ("image/x-quicktime");
 11.1650 +
 11.1651 +#define QTIF_CAPS gst_static_caps_get(&qtif_caps)
 11.1652 +
 11.1653 +/* how many atoms we check before we give up */
 11.1654 +#define QTIF_MAXROUNDS 25
 11.1655 +
 11.1656 +static void
 11.1657 +qtif_type_find (GstTypeFind * tf, gpointer unused)
 11.1658 +{
 11.1659 +  const guint8 *data;
 11.1660 +  gboolean found_idsc = FALSE;
 11.1661 +  gboolean found_idat = FALSE;
 11.1662 +  guint64 offset = 0;
 11.1663 +  guint rounds = 0;
 11.1664 +
 11.1665 +  while ((data = gst_type_find_peek (tf, offset, 8)) != NULL) {
 11.1666 +    guint64 size;
 11.1667 +
 11.1668 +    size = GST_READ_UINT32_BE (data);
 11.1669 +    if (size == 1) {
 11.1670 +      const guint8 *sizedata;
 11.1671 +
 11.1672 +      sizedata = gst_type_find_peek (tf, offset + 8, 8);
 11.1673 +      if (sizedata == NULL)
 11.1674 +        break;
 11.1675 +
 11.1676 +      size = GST_READ_UINT64_BE (sizedata);
 11.1677 +    }
 11.1678 +    if (size < 8)
 11.1679 +      break;
 11.1680 +
 11.1681 +    if (STRNCMP (data + 4, "idsc", 4) == 0)
 11.1682 +      found_idsc = TRUE;
 11.1683 +    if (STRNCMP (data + 4, "idat", 4) == 0)
 11.1684 +      found_idat = TRUE;
 11.1685 +
 11.1686 +    if (found_idsc && found_idat) {
 11.1687 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, QTIF_CAPS);
 11.1688 +      return;
 11.1689 +    }
 11.1690 +
 11.1691 +    offset += size;
 11.1692 +    if (++rounds > QTIF_MAXROUNDS)
 11.1693 +      break;
 11.1694 +  }
 11.1695 +
 11.1696 +  if (found_idsc || found_idat) {
 11.1697 +    gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, QTIF_CAPS);
 11.1698 +    return;
 11.1699 +  }
 11.1700 +};
 11.1701 +
 11.1702 +/*** audio/x-mod ***/
 11.1703 +
 11.1704 +static GstStaticCaps mod_caps = GST_STATIC_CAPS ("audio/x-mod");
 11.1705 +
 11.1706 +#define MOD_CAPS gst_static_caps_get(&mod_caps)
 11.1707 +/* FIXME: M15 CheckType to do */
 11.1708 +static void
 11.1709 +mod_type_find (GstTypeFind * tf, gpointer unused)
 11.1710 +{
 11.1711 +  guint8 *data;
 11.1712 +
 11.1713 +  /* MOD */
 11.1714 +  if ((data = gst_type_find_peek (tf, 1080, 4)) != NULL) {
 11.1715 +    /* Protracker and variants */
 11.1716 +    if ((memcmp (data, "M.K.", 4) == 0) || (memcmp (data, "M!K!", 4) == 0) ||
 11.1717 +        /* Star Tracker */
 11.1718 +        (memcmp (data, "FLT", 3) == 0 && isdigit (data[3])) ||
 11.1719 +        (memcmp (data, "EXO", 3) == 0 && isdigit (data[3])) ||
 11.1720 +        /* Oktalyzer (Amiga) */
 11.1721 +        (memcmp (data, "OKTA", 4) == 0) ||
 11.1722 +        /* Oktalyser (Atari) */
 11.1723 +        (memcmp (data, "CD81", 4) == 0) ||
 11.1724 +        /* Fasttracker */
 11.1725 +        (memcmp (data + 1, "CHN", 3) == 0 && isdigit (data[0])) ||
 11.1726 +        /* Fasttracker or Taketracker */
 11.1727 +        (memcmp (data + 2, "CH", 2) == 0 && isdigit (data[0])
 11.1728 +            && isdigit (data[1])) || (memcmp (data + 2, "CN", 2) == 0
 11.1729 +            && isdigit (data[0]) && isdigit (data[1]))) {
 11.1730 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1731 +      return;
 11.1732 +    }
 11.1733 +  }
 11.1734 +  /* XM */
 11.1735 +  if ((data = gst_type_find_peek (tf, 0, 38)) != NULL) {
 11.1736 +    if (memcmp (data, "Extended Module: ", 17) == 0 && data[37] == 0x1A) {
 11.1737 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1738 +      return;
 11.1739 +    }
 11.1740 +  }
 11.1741 +  /* OKT */
 11.1742 +  if (data || (data = gst_type_find_peek (tf, 0, 8)) != NULL) {
 11.1743 +    if (memcmp (data, "OKTASONG", 8) == 0) {
 11.1744 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1745 +      return;
 11.1746 +    }
 11.1747 +  }
 11.1748 +  if (data || (data = gst_type_find_peek (tf, 0, 4)) != NULL) {
 11.1749 +    /* 669 */
 11.1750 +    if ((memcmp (data, "if", 2) == 0) || (memcmp (data, "JN", 2) == 0)) {
 11.1751 +      gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, MOD_CAPS);
 11.1752 +      return;
 11.1753 +    }
 11.1754 +    /* AMF */
 11.1755 +    if ((memcmp (data, "AMF", 3) == 0 && data[3] > 10 && data[3] < 14) ||
 11.1756 +        /* IT */
 11.1757 +        (memcmp (data, "IMPM", 4) == 0) ||
 11.1758 +        /* MED */
 11.1759 +        (memcmp (data, "MMD0", 4) == 0) || (memcmp (data, "MMD1", 4) == 0) ||
 11.1760 +        /* MTM */
 11.1761 +        (memcmp (data, "MTM", 3) == 0)) {
 11.1762 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1763 +      return;
 11.1764 +    }
 11.1765 +    /* DSM */
 11.1766 +    if (memcmp (data, "RIFF", 4) == 0) {
 11.1767 +      guint8 *data2 = gst_type_find_peek (tf, 8, 4);
 11.1768 +
 11.1769 +      if (data2) {
 11.1770 +        if (memcmp (data2, "DSMF", 4) == 0) {
 11.1771 +          gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1772 +          return;
 11.1773 +        }
 11.1774 +      }
 11.1775 +    }
 11.1776 +    /* FAM */
 11.1777 +    if (memcmp (data, "FAM\xFE", 4) == 0) {
 11.1778 +      guint8 *data2 = gst_type_find_peek (tf, 44, 3);
 11.1779 +
 11.1780 +      if (data2) {
 11.1781 +        if (memcmp (data2, "compare", 3) == 0) {
 11.1782 +          gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1783 +          return;
 11.1784 +        }
 11.1785 +      } else {
 11.1786 +        gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, MOD_CAPS);
 11.1787 +        return;
 11.1788 +      }
 11.1789 +    }
 11.1790 +    /* GDM */
 11.1791 +    if (memcmp (data, "GDM\xFE", 4) == 0) {
 11.1792 +      guint8 *data2 = gst_type_find_peek (tf, 71, 4);
 11.1793 +
 11.1794 +      if (data2) {
 11.1795 +        if (memcmp (data2, "GMFS", 4) == 0) {
 11.1796 +          gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1797 +          return;
 11.1798 +        }
 11.1799 +      } else {
 11.1800 +        gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, MOD_CAPS);
 11.1801 +        return;
 11.1802 +      }
 11.1803 +    }
 11.1804 +  }
 11.1805 +  /* IMF */
 11.1806 +  if ((data = gst_type_find_peek (tf, 60, 4)) != NULL) {
 11.1807 +    if (memcmp (data, "IM10", 4) == 0) {
 11.1808 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1809 +      return;
 11.1810 +    }
 11.1811 +  }
 11.1812 +  /* S3M */
 11.1813 +  if ((data = gst_type_find_peek (tf, 44, 4)) != NULL) {
 11.1814 +    if (memcmp (data, "SCRM", 4) == 0) {
 11.1815 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS);
 11.1816 +      return;
 11.1817 +    }
 11.1818 +  }
 11.1819 +}
 11.1820 +
 11.1821 +/*** application/x-shockwave-flash ***/
 11.1822 +
 11.1823 +static GstStaticCaps swf_caps =
 11.1824 +GST_STATIC_CAPS ("application/x-shockwave-flash");
 11.1825 +#define SWF_CAPS (gst_static_caps_get(&swf_caps))
 11.1826 +static void
 11.1827 +swf_type_find (GstTypeFind * tf, gpointer unused)
 11.1828 +{
 11.1829 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.1830 +
 11.1831 +  if (data && (data[0] == 'F' || data[0] == 'C') &&
 11.1832 +      data[1] == 'W' && data[2] == 'S') {
 11.1833 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SWF_CAPS);
 11.1834 +  }
 11.1835 +}
 11.1836 +
 11.1837 +/*** image/jpeg ***/
 11.1838 +
 11.1839 +static GstStaticCaps jpeg_caps = GST_STATIC_CAPS ("image/jpeg");
 11.1840 +
 11.1841 +#define JPEG_CAPS (gst_static_caps_get(&jpeg_caps))
 11.1842 +static void
 11.1843 +jpeg_type_find (GstTypeFind * tf, gpointer unused)
 11.1844 +{
 11.1845 +  guint8 *data = gst_type_find_peek (tf, 0, 10);
 11.1846 +  guint8 header[2] = { 0xFF, 0xD8 };
 11.1847 +
 11.1848 +  if (data && memcmp (data, header, 2) == 0) {
 11.1849 +    if (memcmp (data + 6, "JFIF", 4) == 0) {
 11.1850 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, JPEG_CAPS);
 11.1851 +    } else if (memcmp (data + 6, "Exif", 4) == 0) {
 11.1852 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, JPEG_CAPS);
 11.1853 +    } else {
 11.1854 +      gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, JPEG_CAPS);
 11.1855 +    }
 11.1856 +  }
 11.1857 +}
 11.1858 +
 11.1859 +/*** image/bmp ***/
 11.1860 +
 11.1861 +static GstStaticCaps bmp_caps = GST_STATIC_CAPS ("image/bmp");
 11.1862 +
 11.1863 +#define BMP_CAPS (gst_static_caps_get(&bmp_caps))
 11.1864 +static void
 11.1865 +bmp_type_find (GstTypeFind * tf, gpointer unused)
 11.1866 +{
 11.1867 +  guint8 *data = gst_type_find_peek (tf, 0, 18);
 11.1868 +
 11.1869 +  if (data && memcmp (data, "BM", 2) == 0) {
 11.1870 +    if ((data[14] == 0x0C ||
 11.1871 +            data[14] == 0x28 ||
 11.1872 +            data[14] == 0xF0) &&
 11.1873 +        data[15] == 0 && data[16] == 0 && data[17] == 0) {
 11.1874 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, BMP_CAPS);
 11.1875 +    }
 11.1876 +  }
 11.1877 +}
 11.1878 +
 11.1879 +/*** image/tiff ***/
 11.1880 +static GstStaticCaps tiff_caps = GST_STATIC_CAPS ("image/tiff, "
 11.1881 +    "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }");
 11.1882 +#define TIFF_CAPS (gst_static_caps_get(&tiff_caps))
 11.1883 +static GstStaticCaps tiff_be_caps = GST_STATIC_CAPS ("image/tiff, "
 11.1884 +    "endianness = (int) BIG_ENDIAN");
 11.1885 +#define TIFF_BE_CAPS (gst_static_caps_get(&tiff_be_caps))
 11.1886 +static GstStaticCaps tiff_le_caps = GST_STATIC_CAPS ("image/tiff, "
 11.1887 +    "endianness = (int) LITTLE_ENDIAN");
 11.1888 +#define TIFF_LE_CAPS (gst_static_caps_get(&tiff_le_caps))
 11.1889 +static void
 11.1890 +tiff_type_find (GstTypeFind * tf, gpointer ununsed)
 11.1891 +{
 11.1892 +  guint8 *data = gst_type_find_peek (tf, 0, 8);
 11.1893 +  guint8 le_header[4] = { 0x49, 0x49, 0x2A, 0x00 };
 11.1894 +  guint8 be_header[4] = { 0x4D, 0x4D, 0x00, 0x2A };
 11.1895 +
 11.1896 +  if (data) {
 11.1897 +    if (memcmp (data, le_header, 4) == 0) {
 11.1898 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, TIFF_LE_CAPS);
 11.1899 +    } else if (memcmp (data, be_header, 4) == 0) {
 11.1900 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, TIFF_BE_CAPS);
 11.1901 +    }
 11.1902 +  }
 11.1903 +}
 11.1904 +
 11.1905 +static GstStaticCaps sds_caps = GST_STATIC_CAPS ("audio/x-sds");
 11.1906 +
 11.1907 +#define SDS_CAPS (gst_static_caps_get(&sds_caps))
 11.1908 +static void
 11.1909 +sds_type_find (GstTypeFind * tf, gpointer ununsed)
 11.1910 +{
 11.1911 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.1912 +  guint8 mask[4] = { 0xFF, 0xFF, 0x80, 0xFF };
 11.1913 +  guint8 match[4] = { 0xF0, 0x7E, 0, 0x01 };
 11.1914 +  gint x;
 11.1915 +
 11.1916 +  if (data) {
 11.1917 +    for (x = 0; x < 4; x++) {
 11.1918 +      if ((data[x] & mask[x]) != match[x]) {
 11.1919 +        return;
 11.1920 +      }
 11.1921 +    }
 11.1922 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SDS_CAPS);
 11.1923 +  }
 11.1924 +}
 11.1925 +
 11.1926 +static GstStaticCaps ircam_caps = GST_STATIC_CAPS ("audio/x-ircam");
 11.1927 +
 11.1928 +#define IRCAM_CAPS (gst_static_caps_get(&ircam_caps))
 11.1929 +static void
 11.1930 +ircam_type_find (GstTypeFind * tf, gpointer ununsed)
 11.1931 +{
 11.1932 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.1933 +  guint8 mask[4] = { 0xFF, 0xFF, 0xF8, 0xFF };
 11.1934 +  guint8 match[4] = { 0x64, 0xA3, 0x00, 0x00 };
 11.1935 +  gint x;
 11.1936 +  gboolean matched = TRUE;
 11.1937 +
 11.1938 +  if (!data) {
 11.1939 +    return;
 11.1940 +  }
 11.1941 +  for (x = 0; x < 4; x++) {
 11.1942 +    if ((data[x] & mask[x]) != match[x]) {
 11.1943 +      matched = FALSE;
 11.1944 +    }
 11.1945 +  }
 11.1946 +  if (matched) {
 11.1947 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, IRCAM_CAPS);
 11.1948 +    return;
 11.1949 +  }
 11.1950 +  /* now try the reverse version */
 11.1951 +  matched = TRUE;
 11.1952 +  for (x = 0; x < 4; x++) {
 11.1953 +    if ((data[x] & mask[3 - x]) != match[3 - x]) {
 11.1954 +      matched = FALSE;
 11.1955 +    }
 11.1956 +  }
 11.1957 +}
 11.1958 +
 11.1959 +
 11.1960 +/*** video/x-matroska ***/
 11.1961 +static GstStaticCaps matroska_caps = GST_STATIC_CAPS ("video/x-matroska");
 11.1962 +
 11.1963 +#define MATROSKA_CAPS (gst_static_caps_get(&matroska_caps))
 11.1964 +static void
 11.1965 +matroska_type_find (GstTypeFind * tf, gpointer ununsed)
 11.1966 +{
 11.1967 +  /* 4 bytes for EBML ID, 1 byte for header length identifier */
 11.1968 +  guint8 *data = gst_type_find_peek (tf, 0, 4 + 1);
 11.1969 +  gint len_mask = 0x80, size = 1, n = 1, total;
 11.1970 +  guint8 probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' };
 11.1971 +
 11.1972 +  if (!data)
 11.1973 +    return;
 11.1974 +
 11.1975 +  /* ebml header? */
 11.1976 +  if (data[0] != 0x1A || data[1] != 0x45 || data[2] != 0xDF || data[3] != 0xA3)
 11.1977 +    return;
 11.1978 +
 11.1979 +  /* length of header */
 11.1980 +  total = data[4];
 11.1981 +  while (size <= 8 && !(total & len_mask)) {
 11.1982 +    size++;
 11.1983 +    len_mask >>= 1;
 11.1984 +  }
 11.1985 +  if (size > 8)
 11.1986 +    return;
 11.1987 +  total &= (len_mask - 1);
 11.1988 +  while (n < size)
 11.1989 +    total = (total << 8) | data[4 + n++];
 11.1990 +
 11.1991 +  /* get new data for full header, 4 bytes for EBML ID,
 11.1992 +   * EBML length tag and the actual header */
 11.1993 +  data = gst_type_find_peek (tf, 0, 4 + size + total);
 11.1994 +  if (!data)
 11.1995 +    return;
 11.1996 +
 11.1997 +  /* the header must contain the document type 'matroska'. For now,
 11.1998 +   * we don't parse the whole header but simply check for the
 11.1999 +   * availability of that array of characters inside the header.
 11.2000 +   * Not fully fool-proof, but good enough. */
 11.2001 +  for (n = 4 + size; n <= 4 + size + total - sizeof (probe_data); n++)
 11.2002 +    if (!memcmp (&data[n], probe_data, sizeof (probe_data))) {
 11.2003 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MATROSKA_CAPS);
 11.2004 +      break;
 11.2005 +    }
 11.2006 +}
 11.2007 +
 11.2008 +/*** video/x-dv ***/
 11.2009 +
 11.2010 +static GstStaticCaps dv_caps = GST_STATIC_CAPS ("video/x-dv, "
 11.2011 +    "systemstream = (boolean) true");
 11.2012 +#define DV_CAPS (gst_static_caps_get(&dv_caps))
 11.2013 +static void
 11.2014 +dv_type_find (GstTypeFind * tf, gpointer private)
 11.2015 +{
 11.2016 +  guint8 *data;
 11.2017 +
 11.2018 +  data = gst_type_find_peek (tf, 0, 5);
 11.2019 +
 11.2020 +  /* check for DIF  and DV flag */
 11.2021 +  if (data && (data[0] == 0x1f) && (data[1] == 0x07) && (data[2] == 0x00) &&
 11.2022 +      ((data[4] & 0x01) == 0)) {
 11.2023 +    gchar *format;
 11.2024 +    GstCaps *caps = gst_caps_copy (DV_CAPS);
 11.2025 +
 11.2026 +    if (data[3] & 0x80) {
 11.2027 +      format = "PAL";
 11.2028 +    } else {
 11.2029 +      format = "NTSC";
 11.2030 +    }
 11.2031 +    gst_structure_set (gst_caps_get_structure (caps, 0), "format",
 11.2032 +        G_TYPE_STRING, format, NULL);
 11.2033 +
 11.2034 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, caps);
 11.2035 +    gst_caps_unref (caps);
 11.2036 +  }
 11.2037 +}
 11.2038 +
 11.2039 +
 11.2040 +/*** application/ogg and application/x-annodex ***/
 11.2041 +static GstStaticCaps ogg_caps = GST_STATIC_CAPS ("application/ogg");
 11.2042 +static GstStaticCaps annodex_caps = GST_STATIC_CAPS ("application/x-annodex");
 11.2043 +
 11.2044 +#define OGGANX_CAPS (gst_static_caps_get(&annodex_caps))
 11.2045 +
 11.2046 +static void
 11.2047 +ogganx_type_find (GstTypeFind * tf, gpointer private)
 11.2048 +{
 11.2049 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.2050 +
 11.2051 +  if ((data != NULL) && (memcmp (data, "OggS", 4) == 0)) {
 11.2052 +
 11.2053 +    /* Check for an annodex fishbone header */
 11.2054 +    data = gst_type_find_peek (tf, 28, 8);
 11.2055 +    if (data && memcmp (data, "fishead\0", 8) == 0)
 11.2056 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, OGGANX_CAPS);
 11.2057 +
 11.2058 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM,
 11.2059 +        gst_static_caps_get (&ogg_caps));
 11.2060 +  }
 11.2061 +}
 11.2062 +
 11.2063 +/*** audio/x-vorbis ***/
 11.2064 +static GstStaticCaps vorbis_caps = GST_STATIC_CAPS ("audio/x-vorbis");
 11.2065 +
 11.2066 +#define VORBIS_CAPS (gst_static_caps_get(&vorbis_caps))
 11.2067 +static void
 11.2068 +vorbis_type_find (GstTypeFind * tf, gpointer private)
 11.2069 +{
 11.2070 +  guint8 *data = gst_type_find_peek (tf, 0, 30);
 11.2071 +
 11.2072 +  if (data) {
 11.2073 +    guint blocksize_0;
 11.2074 +    guint blocksize_1;
 11.2075 +
 11.2076 +    /* 1 byte packet type (identification=0x01)
 11.2077 +       6 byte string "vorbis"
 11.2078 +       4 byte vorbis version */
 11.2079 +    if (memcmp (data, "\001vorbis\000\000\000\000", 11) != 0)
 11.2080 +      return;
 11.2081 +    data += 11;
 11.2082 +    /* 1 byte channels must be != 0 */
 11.2083 +    if (data[0] == 0)
 11.2084 +      return;
 11.2085 +    data++;
 11.2086 +    /* 4 byte samplerate must be != 0 */
 11.2087 +    if (*((guint32 *) data) == 0)
 11.2088 +      return;
 11.2089 +    data += 16;
 11.2090 +    /* blocksize checks */
 11.2091 +    blocksize_0 = data[0] & 0x0F;
 11.2092 +    blocksize_1 = (data[0] & 0xF0) >> 4;
 11.2093 +    if (blocksize_0 > blocksize_1)
 11.2094 +      return;
 11.2095 +    if (blocksize_0 < 6 || blocksize_0 > 13)
 11.2096 +      return;
 11.2097 +    if (blocksize_1 < 6 || blocksize_1 > 13)
 11.2098 +      return;
 11.2099 +    data++;
 11.2100 +    /* framing bit */
 11.2101 +    if ((data[0] & 0x01) != 1)
 11.2102 +      return;
 11.2103 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, VORBIS_CAPS);
 11.2104 +  }
 11.2105 +}
 11.2106 +
 11.2107 +/*** video/x-theora ***/
 11.2108 +
 11.2109 +static GstStaticCaps theora_caps = GST_STATIC_CAPS ("video/x-theora");
 11.2110 +
 11.2111 +#define THEORA_CAPS (gst_static_caps_get(&theora_caps))
 11.2112 +static void
 11.2113 +theora_type_find (GstTypeFind * tf, gpointer private)
 11.2114 +{
 11.2115 +  guint8 *data = gst_type_find_peek (tf, 0, 7); //42);
 11.2116 +
 11.2117 +  if (data) {
 11.2118 +    if (data[0] != 0x80)
 11.2119 +      return;
 11.2120 +    if (memcmp (&data[1], "theora", 6) != 0)
 11.2121 +      return;
 11.2122 +    /* FIXME: make this more reliable when specs are out */
 11.2123 +
 11.2124 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, THEORA_CAPS);
 11.2125 +  }
 11.2126 +}
 11.2127 +
 11.2128 +/*** application/x-ogm-video or audio***/
 11.2129 +
 11.2130 +static GstStaticCaps ogmvideo_caps =
 11.2131 +GST_STATIC_CAPS ("application/x-ogm-video");
 11.2132 +#define OGMVIDEO_CAPS (gst_static_caps_get(&ogmvideo_caps))
 11.2133 +static void
 11.2134 +ogmvideo_type_find (GstTypeFind * tf, gpointer private)
 11.2135 +{
 11.2136 +  guint8 *data = gst_type_find_peek (tf, 0, 9);
 11.2137 +
 11.2138 +  if (data) {
 11.2139 +    if (memcmp (data, "\001video\000\000\000", 9) != 0)
 11.2140 +      return;
 11.2141 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, OGMVIDEO_CAPS);
 11.2142 +  }
 11.2143 +}
 11.2144 +
 11.2145 +static GstStaticCaps ogmaudio_caps =
 11.2146 +GST_STATIC_CAPS ("application/x-ogm-audio");
 11.2147 +#define OGMAUDIO_CAPS (gst_static_caps_get(&ogmaudio_caps))
 11.2148 +static void
 11.2149 +ogmaudio_type_find (GstTypeFind * tf, gpointer private)
 11.2150 +{
 11.2151 +  guint8 *data = gst_type_find_peek (tf, 0, 9);
 11.2152 +
 11.2153 +  if (data) {
 11.2154 +    if (memcmp (data, "\001audio\000\000\000", 9) != 0)
 11.2155 +      return;
 11.2156 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, OGMAUDIO_CAPS);
 11.2157 +  }
 11.2158 +}
 11.2159 +
 11.2160 +static GstStaticCaps ogmtext_caps = GST_STATIC_CAPS ("application/x-ogm-text");
 11.2161 +
 11.2162 +#define OGMTEXT_CAPS (gst_static_caps_get(&ogmtext_caps))
 11.2163 +static void
 11.2164 +ogmtext_type_find (GstTypeFind * tf, gpointer private)
 11.2165 +{
 11.2166 +  guint8 *data = gst_type_find_peek (tf, 0, 9);
 11.2167 +
 11.2168 +  if (data) {
 11.2169 +    if (memcmp (data, "\001text\000\000\000\000", 9) != 0)
 11.2170 +      return;
 11.2171 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, OGMTEXT_CAPS);
 11.2172 +  }
 11.2173 +}
 11.2174 +
 11.2175 +/*** audio/x-speex ***/
 11.2176 +
 11.2177 +static GstStaticCaps speex_caps = GST_STATIC_CAPS ("audio/x-speex");
 11.2178 +
 11.2179 +#define SPEEX_CAPS (gst_static_caps_get(&speex_caps))
 11.2180 +static void
 11.2181 +speex_type_find (GstTypeFind * tf, gpointer private)
 11.2182 +{
 11.2183 +  guint8 *data = gst_type_find_peek (tf, 0, 80);
 11.2184 +
 11.2185 +  if (data) {
 11.2186 +    /* 8 byte string "Speex   "
 11.2187 +       24 byte speex version string + int */
 11.2188 +    if (memcmp (data, "Speex   ", 8) != 0)
 11.2189 +      return;
 11.2190 +    data += 32;
 11.2191 +
 11.2192 +    /* 4 byte header size >= 80 */
 11.2193 +    if (GST_READ_UINT32_LE (data) < 80)
 11.2194 +      return;
 11.2195 +    data += 4;
 11.2196 +
 11.2197 +    /* 4 byte sample rate <= 48000 */
 11.2198 +    if (GST_READ_UINT32_LE (data) > 48000)
 11.2199 +      return;
 11.2200 +    data += 4;
 11.2201 +
 11.2202 +    /* currently there are only 3 speex modes. */
 11.2203 +    if (GST_READ_UINT32_LE (data) > 3)
 11.2204 +      return;
 11.2205 +    data += 12;
 11.2206 +
 11.2207 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SPEEX_CAPS);
 11.2208 +  }
 11.2209 +}
 11.2210 +
 11.2211 +/*** application/x-ogg-skeleton ***/
 11.2212 +static GstStaticCaps ogg_skeleton_caps =
 11.2213 +GST_STATIC_CAPS ("application/x-ogg-skeleton, parsed=(boolean)FALSE");
 11.2214 +#define OGG_SKELETON_CAPS (gst_static_caps_get(&ogg_skeleton_caps))
 11.2215 +static void
 11.2216 +oggskel_type_find (GstTypeFind * tf, gpointer private)
 11.2217 +{
 11.2218 +  guint8 *data = gst_type_find_peek (tf, 0, 12);
 11.2219 +
 11.2220 +  if (data) {
 11.2221 +    /* 8 byte string "fishead\0" for the ogg skeleton stream */
 11.2222 +    if (memcmp (data, "fishead\0", 8) != 0)
 11.2223 +      return;
 11.2224 +    data += 8;
 11.2225 +
 11.2226 +    /* Require that the header contains version 3.0 */
 11.2227 +    if (GST_READ_UINT16_LE (data) != 3)
 11.2228 +      return;
 11.2229 +    data += 2;
 11.2230 +    if (GST_READ_UINT16_LE (data) != 0)
 11.2231 +      return;
 11.2232 +
 11.2233 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, OGG_SKELETON_CAPS);
 11.2234 +  }
 11.2235 +}
 11.2236 +
 11.2237 +static GstStaticCaps cmml_caps = GST_STATIC_CAPS ("text/x-cmml");
 11.2238 +
 11.2239 +#define CMML_CAPS (gst_static_caps_get(&cmml_caps))
 11.2240 +static void
 11.2241 +cmml_type_find (GstTypeFind * tf, gpointer private)
 11.2242 +{
 11.2243 +  /* Header is 12 bytes minimum (though we don't check the minor version */
 11.2244 +  guint8 *data = gst_type_find_peek (tf, 0, 12);
 11.2245 +
 11.2246 +  if (data) {
 11.2247 +
 11.2248 +    /* 8 byte string "CMML\0\0\0\0" for the magic number */
 11.2249 +    if (memcmp (data, "CMML\0\0\0\0", 8) != 0)
 11.2250 +      return;
 11.2251 +    data += 8;
 11.2252 +
 11.2253 +    /* Require that the header contains at least version 2.0 */
 11.2254 +    if (GST_READ_UINT16_LE (data) < 2)
 11.2255 +      return;
 11.2256 +
 11.2257 +    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, CMML_CAPS);
 11.2258 +  }
 11.2259 +}
 11.2260 +
 11.2261 +/*** application/x-tar ***/
 11.2262 +
 11.2263 +static GstStaticCaps tar_caps = GST_STATIC_CAPS ("application/x-tar");
 11.2264 +
 11.2265 +#define TAR_CAPS (gst_static_caps_get(&tar_caps))
 11.2266 +#define OLDGNU_MAGIC "ustar  "  /* 7 chars and a NUL */
 11.2267 +#define NEWGNU_MAGIC "ustar"    /* 5 chars and a NUL */
 11.2268 +static void
 11.2269 +tar_type_find (GstTypeFind * tf, gpointer unused)
 11.2270 +{
 11.2271 +  guint8 *data = gst_type_find_peek (tf, 257, 8);
 11.2272 +
 11.2273 +  /* of course we are not certain, but we don't want other typefind funcs
 11.2274 +   * to detect formats of files within the tar archive, e.g. mp3s */
 11.2275 +  if (data) {
 11.2276 +    if (memcmp (data, OLDGNU_MAGIC, 8) == 0) {  /* sic */
 11.2277 +      gst_type_find_suggest (tf, GST_TYPE_FIND_NEARLY_CERTAIN, TAR_CAPS);
 11.2278 +    } else if (memcmp (data, NEWGNU_MAGIC, 6) == 0 &&   /* sic */
 11.2279 +        g_ascii_isdigit (data[6]) && g_ascii_isdigit (data[7])) {
 11.2280 +      gst_type_find_suggest (tf, GST_TYPE_FIND_NEARLY_CERTAIN, TAR_CAPS);
 11.2281 +    }
 11.2282 +  }
 11.2283 +}
 11.2284 +
 11.2285 +/*** application/x-ar ***/
 11.2286 +
 11.2287 +static GstStaticCaps ar_caps = GST_STATIC_CAPS ("application/x-ar");
 11.2288 +
 11.2289 +#define AR_CAPS (gst_static_caps_get(&ar_caps))
 11.2290 +static void
 11.2291 +ar_type_find (GstTypeFind * tf, gpointer unused)
 11.2292 +{
 11.2293 +  guint8 *data = gst_type_find_peek (tf, 0, 24);
 11.2294 +
 11.2295 +  if (data && memcmp (data, "!<arch>", 7) == 0) {
 11.2296 +    gint i;
 11.2297 +
 11.2298 +    for (i = 7; i < 24; ++i) {
 11.2299 +      if (!g_ascii_isprint (data[i]) && data[i] != '\n') {
 11.2300 +        gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, AR_CAPS);
 11.2301 +      }
 11.2302 +    }
 11.2303 +
 11.2304 +    gst_type_find_suggest (tf, GST_TYPE_FIND_NEARLY_CERTAIN, AR_CAPS);
 11.2305 +  }
 11.2306 +}
 11.2307 +
 11.2308 +/*** audio/x-au ***/
 11.2309 +
 11.2310 +/* NOTE: we cannot replace this function with TYPE_FIND_REGISTER_START_WITH,
 11.2311 + * as it is only possible to register one typefind factory per 'name'
 11.2312 + * (which is in this case the caps), and the first one would be replaced by
 11.2313 + * the second one. */
 11.2314 +static GstStaticCaps au_caps = GST_STATIC_CAPS ("audio/x-au");
 11.2315 +
 11.2316 +#define AU_CAPS (gst_static_caps_get(&au_caps))
 11.2317 +static void
 11.2318 +au_type_find (GstTypeFind * tf, gpointer unused)
 11.2319 +{
 11.2320 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.2321 +
 11.2322 +  if (data) {
 11.2323 +    if (memcmp (data, ".snd", 4) == 0 || memcmp (data, "dns.", 4) == 0) {
 11.2324 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, AU_CAPS);
 11.2325 +    }
 11.2326 +  }
 11.2327 +}
 11.2328 +
 11.2329 +
 11.2330 +/*** video/x-nuv ***/
 11.2331 +
 11.2332 +/* NOTE: we cannot replace this function with TYPE_FIND_REGISTER_START_WITH,
 11.2333 + * as it is only possible to register one typefind factory per 'name'
 11.2334 + * (which is in this case the caps), and the first one would be replaced by
 11.2335 + * the second one. */
 11.2336 +static GstStaticCaps nuv_caps = GST_STATIC_CAPS ("video/x-nuv");
 11.2337 +
 11.2338 +#define NUV_CAPS (gst_static_caps_get(&nuv_caps))
 11.2339 +static void
 11.2340 +nuv_type_find (GstTypeFind * tf, gpointer unused)
 11.2341 +{
 11.2342 +  guint8 *data = gst_type_find_peek (tf, 0, 11);
 11.2343 +
 11.2344 +  if (data) {
 11.2345 +    if (memcmp (data, "MythTVVideo", 11) == 0
 11.2346 +        || memcmp (data, "NuppelVideo", 11) == 0) {
 11.2347 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, NUV_CAPS);
 11.2348 +    }
 11.2349 +  }
 11.2350 +}
 11.2351 +
 11.2352 +/*** audio/x-paris ***/
 11.2353 +/* NOTE: do not replace this function with two TYPE_FIND_REGISTER_START_WITH */
 11.2354 +static GstStaticCaps paris_caps = GST_STATIC_CAPS ("audio/x-paris");
 11.2355 +
 11.2356 +#define PARIS_CAPS (gst_static_caps_get(&paris_caps))
 11.2357 +static void
 11.2358 +paris_type_find (GstTypeFind * tf, gpointer unused)
 11.2359 +{
 11.2360 +  guint8 *data = gst_type_find_peek (tf, 0, 4);
 11.2361 +
 11.2362 +  if (data) {
 11.2363 +    if (memcmp (data, " paf", 4) == 0 || memcmp (data, "fap ", 4) == 0) {
 11.2364 +      gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, PARIS_CAPS);
 11.2365 +    }
 11.2366 +  }
 11.2367 +}
 11.2368 +
 11.2369 +/*** audio/iLBC-sh ***/
 11.2370 +/* NOTE: do not replace this function with two TYPE_FIND_REGISTER_START_WITH */
 11.2371 +static GstStaticCaps ilbc_caps = GST_STATIC_CAPS ("audio/iLBC-sh");
 11.2372 +
 11.2373 +#define ILBC_CAPS (gst_static_caps_get(&ilbc_caps))
 11.2374 +static void
 11.2375 +ilbc_type_find (GstTypeFind * tf, gpointer unused)
 11.2376 +{
 11.2377 +  guint8 *data = gst_type_find_peek (tf, 0, 8);
 11.2378 +
 11.2379 +  if (data) {
 11.2380 +    if (memcmp (data, "#!iLBC30", 8) == 0 || memcmp (data, "#!iLBC20", 8) == 0) {
 11.2381 +      gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, ILBC_CAPS);
 11.2382 +    }
 11.2383 +  }
 11.2384 +}
 11.2385 +
 11.2386 +/*** application/x-ms-dos-executable ***/
 11.2387 +
 11.2388 +static GstStaticCaps msdos_caps =
 11.2389 +GST_STATIC_CAPS ("application/x-ms-dos-executable");
 11.2390 +#define MSDOS_CAPS (gst_static_caps_get(&msdos_caps))
 11.2391 +/* see http://www.madchat.org/vxdevl/papers/winsys/pefile/pefile.htm */
 11.2392 +static void
 11.2393 +msdos_type_find (GstTypeFind * tf, gpointer unused)
 11.2394 +{
 11.2395 +  guint8 *data = gst_type_find_peek (tf, 0, 64);
 11.2396 +
 11.2397 +  if (data && data[0] == 'M' && data[1] == 'Z' &&
 11.2398 +      GST_READ_UINT16_LE (data + 8) == 4) {
 11.2399 +    guint32 pe_offset = GST_READ_UINT32_LE (data + 60);
 11.2400 +
 11.2401 +    data = gst_type_find_peek (tf, pe_offset, 2);
 11.2402 +    if (data && data[0] == 'P' && data[1] == 'E') {
 11.2403 +      gst_type_find_suggest (tf, GST_TYPE_FIND_NEARLY_CERTAIN, MSDOS_CAPS);
 11.2404 +    }
 11.2405 +  }
 11.2406 +}
 11.2407 +
 11.2408 +/*** application/x-mmsh ***/
 11.2409 +
 11.2410 +static GstStaticCaps mmsh_caps = GST_STATIC_CAPS ("application/x-mmsh");
 11.2411 +
 11.2412 +#define MMSH_CAPS gst_static_caps_get(&mmsh_caps)
 11.2413 +
 11.2414 +/* This is to recognise mssh-over-http */
 11.2415 +static void
 11.2416 +mmsh_type_find (GstTypeFind * tf, gpointer unused)
 11.2417 +{
 11.2418 +  static const guint8 asf_marker[16] = { 0x30, 0x26, 0xb2, 0x75, 0x8e, 0x66,
 11.2419 +    0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
 11.2420 +  };
 11.2421 +
 11.2422 +  guint8 *data;
 11.2423 +
 11.2424 +  data = gst_type_find_peek (tf, 0, 2 + 2 + 4 + 2 + 2 + 16);
 11.2425 +  if (data && data[0] == 0x24 && data[1] == 0x48 &&
 11.2426 +      GST_READ_UINT16_LE (data + 2) > 2 + 2 + 4 + 2 + 2 + 16 &&
 11.2427 +      memcmp (data + 2 + 2 + 4 + 2 + 2, asf_marker, 16) == 0) {
 11.2428 +    GstCaps *caps = gst_caps_copy (MMSH_CAPS);
 11.2429 +
 11.2430 +    gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, caps);
 11.2431 +    gst_caps_unref (caps);
 11.2432 +    return;
 11.2433 +  }
 11.2434 +}
 11.2435 +
 11.2436 +/*** generic typefind for streams that have some data at a specific position***/
 11.2437 +typedef struct
 11.2438 +{
 11.2439 +  const guint8 *data;
 11.2440 +  guint size;
 11.2441 +  guint probability;
 11.2442 +  GstCaps *caps;
 11.2443 +}
 11.2444 +GstTypeFindData;
 11.2445 +
 11.2446 +static void
 11.2447 +start_with_type_find (GstTypeFind * tf, gpointer private)
 11.2448 +{
 11.2449 +  GstTypeFindData *start_with = (GstTypeFindData *) private;
 11.2450 +  guint8 *data;
 11.2451 +
 11.2452 +  GST_LOG ("trying to find mime type %s with the first %u bytes of data",
 11.2453 +      gst_structure_get_name (gst_caps_get_structure (start_with->caps, 0)),
 11.2454 +      start_with->size);
 11.2455 +  data = gst_type_find_peek (tf, 0, start_with->size);
 11.2456 +  if (data && memcmp (data, start_with->data, start_with->size) == 0) {
 11.2457 +    gst_type_find_suggest (tf, start_with->probability, start_with->caps);
 11.2458 +  }
 11.2459 +}
 11.2460 +
 11.2461 +static void
 11.2462 +sw_data_destroy (GstTypeFindData * sw_data)
 11.2463 +{
 11.2464 +  if (G_LIKELY (sw_data->caps != NULL))
 11.2465 +    gst_caps_unref (sw_data->caps);
 11.2466 +  g_free (sw_data);
 11.2467 +}
 11.2468 +
 11.2469 +#define TYPE_FIND_REGISTER_START_WITH(plugin,name,rank,ext,_data,_size,_probability)\
 11.2470 +G_BEGIN_DECLS{                                                          \
 11.2471 +  GstTypeFindData *sw_data = g_new (GstTypeFindData, 1);                \
 11.2472 +  sw_data->data = (const guint8 *)_data;                                \
 11.2473 +  sw_data->size = _size;                                                \
 11.2474 +  sw_data->probability = _probability;                                  \
 11.2475 +  sw_data->caps = gst_caps_new_simple (name, NULL);                     \
 11.2476 +  if (!gst_type_find_register (plugin, name, rank, start_with_type_find,\
 11.2477 +                      ext, sw_data->caps, sw_data,                      \
 11.2478 +                     (GDestroyNotify) (sw_data_destroy))) {             \
 11.2479 +    gst_caps_unref (sw_data->caps);                                     \
 11.2480 +    g_free (sw_data);                                                   \
 11.2481 +  }                                                                     \
 11.2482 +}G_END_DECLS
 11.2483 +
 11.2484 +/*** same for riff types ***/
 11.2485 +
 11.2486 +static void
 11.2487 +riff_type_find (GstTypeFind * tf, gpointer private)
 11.2488 +{
 11.2489 +  GstTypeFindData *riff_data = (GstTypeFindData *) private;
 11.2490 +  guint8 *data = gst_type_find_peek (tf, 0, 12);
 11.2491 +
 11.2492 +  if (data && memcmp (data, "RIFF", 4) == 0) {
 11.2493 +    data += 8;
 11.2494 +    if (memcmp (data, riff_data->data, 4) == 0)
 11.2495 +      gst_type_find_suggest (tf, riff_data->probability, riff_data->caps);
 11.2496 +  }
 11.2497 +}
 11.2498 +
 11.2499 +#define TYPE_FIND_REGISTER_RIFF(plugin,name,rank,ext,_data)             \
 11.2500 +G_BEGIN_DECLS{                                                          \
 11.2501 +  GstTypeFindData *sw_data = g_new (GstTypeFindData, 1);                \
 11.2502 +  sw_data->data = (gpointer)_data;                                      \
 11.2503 +  sw_data->size = 4;                                                    \
 11.2504 +  sw_data->probability = GST_TYPE_FIND_MAXIMUM;                         \
 11.2505 +  sw_data->caps = gst_caps_new_simple (name, NULL);                     \
 11.2506 +  if (!gst_type_find_register (plugin, name, rank, riff_type_find,      \
 11.2507 +                      ext, sw_data->caps, sw_data,                      \
 11.2508 +                      (GDestroyNotify) (sw_data_destroy))) {            \
 11.2509 +    gst_caps_unref (sw_data->caps);                                     \
 11.2510 +    g_free (sw_data);                                                   \
 11.2511 +  }                                                                     \
 11.2512 +}G_END_DECLS
 11.2513 +
 11.2514 +
 11.2515 +
 11.2516 +/*** plugin initialization ***/
 11.2517 +
 11.2518 +#define TYPE_FIND_REGISTER(plugin,name,rank,func,ext,caps,priv,notify) \
 11.2519 +G_BEGIN_DECLS{\
 11.2520 +  if (!gst_type_find_register (plugin, name, rank, func, ext, caps, priv, notify))\
 11.2521 +    return FALSE; \
 11.2522 +}G_END_DECLS
 11.2523 +static gboolean
 11.2524 +plugin_init (GstPlugin * plugin)
 11.2525 +{
 11.2526 +  /* can't initialize this via a struct as caps can't be statically initialized */
 11.2527 +
 11.2528 +  /* note: asx/wax/wmx are XML files, asf doesn't handle them */
 11.2529 +  /* FIXME-0.11: these should be const,
 11.2530 +     this requires gstreamer/gst/gsttypefind::gst_type_find_register()
 11.2531 +     to have define the parameter as const
 11.2532 +   */
 11.2533 +  static gchar *asf_exts[] = { "asf", "wm", "wma", "wmv", NULL };
 11.2534 +  static gchar *au_exts[] = { "au", "snd", NULL };
 11.2535 +  static gchar *avi_exts[] = { "avi", NULL };
 11.2536 +  static gchar *cdxa_exts[] = { "dat", NULL };
 11.2537 +  static gchar *flac_exts[] = { "flac", NULL };
 11.2538 +  static gchar *flx_exts[] = { "flc", "fli", NULL };
 11.2539 +  static gchar *id3_exts[] =
 11.2540 +      { "mp3", "mp2", "mp1", "mpga", "ogg", "flac", "tta", NULL };
 11.2541 +  static gchar *apetag_exts[] = { "ape", "mpc", "wv", NULL };   /* and mp3 and wav? */
 11.2542 +  static gchar *tta_exts[] = { "tta", NULL };
 11.2543 +  static gchar *mod_exts[] = { "669", "amf", "dsm", "gdm", "far", "imf",
 11.2544 +    "it", "med", "mod", "mtm", "okt", "sam",
 11.2545 +    "s3m", "stm", "stx", "ult", "xm", NULL
 11.2546 +  };
 11.2547 +  static gchar *mp3_exts[] = { "mp3", "mp2", "mp1", "mpga", NULL };
 11.2548 +  static gchar *ac3_exts[] = { "ac3", NULL };
 11.2549 +  static gchar *musepack_exts[] = { "mpc", NULL };
 11.2550 +  static gchar *mpeg_sys_exts[] = { "mpe", "mpeg", "mpg", NULL };
 11.2551 +  static gchar *mpeg_video_exts[] = { "mpv", "mpeg", "mpg", NULL };
 11.2552 +  static gchar *mpeg_ts_exts[] = { "ts", NULL };
 11.2553 +  static gchar *ogg_exts[] = { "anx", "ogg", "ogm", NULL };
 11.2554 +  static gchar *qt_exts[] = { "mov", NULL };
 11.2555 +  static gchar *qtif_exts[] = { "qif", "qtif", "qti", NULL };
 11.2556 +  static gchar *rm_exts[] = { "ra", "ram", "rm", "rmvb", NULL };
 11.2557 +  static gchar *swf_exts[] = { "swf", "swfl", NULL };
 11.2558 +  static gchar *utf8_exts[] = { "txt", NULL };
 11.2559 +  static gchar *wav_exts[] = { "wav", NULL };
 11.2560 +  static gchar *aiff_exts[] = { "aiff", "aif", "aifc", NULL };
 11.2561 +  static gchar *svx_exts[] = { "iff", "svx", NULL };
 11.2562 +  static gchar *paris_exts[] = { "paf", NULL };
 11.2563 +  static gchar *nist_exts[] = { "nist", NULL };
 11.2564 +  static gchar *voc_exts[] = { "voc", NULL };
 11.2565 +  static gchar *sds_exts[] = { "sds", NULL };
 11.2566 +  static gchar *ircam_exts[] = { "sf", NULL };
 11.2567 +  static gchar *w64_exts[] = { "w64", NULL };
 11.2568 +  static gchar *shn_exts[] = { "shn", NULL };
 11.2569 +  static gchar *ape_exts[] = { "ape", NULL };
 11.2570 +  static gchar *uri_exts[] = { "ram", NULL };
 11.2571 +  static gchar *smil_exts[] = { "smil", NULL };
 11.2572 +  static gchar *html_exts[] = { "htm", "html", NULL };
 11.2573 +  static gchar *xml_exts[] = { "xml", NULL };
 11.2574 +  static gchar *jpeg_exts[] = { "jpg", "jpe", "jpeg", NULL };
 11.2575 +  static gchar *gif_exts[] = { "gif", NULL };
 11.2576 +  static gchar *png_exts[] = { "png", NULL };
 11.2577 +  static gchar *bmp_exts[] = { "bmp", NULL };
 11.2578 +  static gchar *tiff_exts[] = { "tif", "tiff", NULL };
 11.2579 +  static gchar *matroska_exts[] = { "mkv", "mka", NULL };
 11.2580 +  static gchar *mve_exts[] = { "mve", NULL };
 11.2581 +  static gchar *dv_exts[] = { "dv", "dif", NULL };
 11.2582 +  static gchar *amr_exts[] = { "amr", NULL };
 11.2583 +  static gchar *ilbc_exts[] = { "ilbc", NULL };
 11.2584 +  static gchar *sid_exts[] = { "sid", NULL };
 11.2585 +  static gchar *xcf_exts[] = { "xcf", NULL };
 11.2586 +  static gchar *mng_exts[] = { "mng", NULL };
 11.2587 +  static gchar *jng_exts[] = { "jng", NULL };
 11.2588 +  static gchar *xpm_exts[] = { "xpm", NULL };
 11.2589 +  static gchar *ras_exts[] = { "ras", NULL };
 11.2590 +  static gchar *bz2_exts[] = { "bz2", NULL };
 11.2591 +  static gchar *gz_exts[] = { "gz", NULL };
 11.2592 +  static gchar *zip_exts[] = { "zip", NULL };
 11.2593 +  static gchar *compress_exts[] = { "Z", NULL };
 11.2594 +  static gchar *m4a_exts[] = { "m4a", NULL };
 11.2595 +  static gchar *q3gp_exts[] = { "3gp", NULL };
 11.2596 +  static gchar *aac_exts[] = { "aac", NULL };
 11.2597 +  static gchar *spc_exts[] = { "spc", NULL };
 11.2598 +  static gchar *wavpack_exts[] = { "wv", "wvp", NULL };
 11.2599 +  static gchar *wavpack_correction_exts[] = { "wvc", NULL };
 11.2600 +  static gchar *rar_exts[] = { "rar", NULL };
 11.2601 +  static gchar *tar_exts[] = { "tar", NULL };
 11.2602 +  static gchar *ar_exts[] = { "a", NULL };
 11.2603 +  static gchar *msdos_exts[] = { "dll", "exe", "ocx", "sys", "scr",
 11.2604 +    "msstyles", "cpl", NULL
 11.2605 +  };
 11.2606 +  static gchar *flv_exts[] = { "flv", NULL };
 11.2607 +  static gchar *m4v_exts[] = { "m4v", NULL };
 11.2608 +  static gchar *nuv_exts[] = { "nuv", NULL };
 11.2609 +
 11.2610 +  GST_DEBUG_CATEGORY_INIT (type_find_debug, "typefindfunctions",
 11.2611 +      GST_DEBUG_FG_GREEN | GST_DEBUG_BG_RED, "generic type find functions");
 11.2612 +
 11.2613 +  /* must use strings, macros don't accept initializers */
 11.2614 +  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-ms-asf", GST_RANK_SECONDARY,
 11.2615 +      asf_exts,
 11.2616 +      "\060\046\262\165\216\146\317\021\246\331\000\252\000\142\316\154", 16,
 11.2617 +      GST_TYPE_FIND_MAXIMUM);
 11.2618 +  TYPE_FIND_REGISTER (plugin, "audio/x-musepack", GST_RANK_PRIMARY,
 11.2619 +      musepack_type_find, musepack_exts, MUSEPACK_CAPS, NULL, NULL);
 11.2620 +  TYPE_FIND_REGISTER (plugin, "audio/x-au", GST_RANK_MARGINAL,
 11.2621 +      au_type_find, au_exts, AU_CAPS, NULL, NULL);
 11.2622 +  TYPE_FIND_REGISTER_RIFF (plugin, "video/x-msvideo", GST_RANK_PRIMARY,
 11.2623 +      avi_exts, "AVI ");
 11.2624 +  TYPE_FIND_REGISTER_RIFF (plugin, "video/x-cdxa", GST_RANK_PRIMARY,
 11.2625 +      cdxa_exts, "CDXA");
 11.2626 +  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-vcd", GST_RANK_PRIMARY,
 11.2627 +      cdxa_exts, "\000\377\377\377\377\377\377\377\377\377\377\000", 12,
 11.2628 +      GST_TYPE_FIND_MAXIMUM);
 11.2629 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-flac", GST_RANK_PRIMARY,
 11.2630 +      flac_exts, "fLaC", 4, GST_TYPE_FIND_MAXIMUM);
 11.2631 +  TYPE_FIND_REGISTER (plugin, "video/x-fli", GST_RANK_MARGINAL, flx_type_find,
 11.2632 +      flx_exts, FLX_CAPS, NULL, NULL);
 11.2633 +  TYPE_FIND_REGISTER (plugin, "application/x-id3v2", GST_RANK_PRIMARY + 3,
 11.2634 +      id3v2_type_find, id3_exts, ID3_CAPS, NULL, NULL);
 11.2635 +  TYPE_FIND_REGISTER (plugin, "application/x-id3v1", GST_RANK_PRIMARY + 1,
 11.2636 +      id3v1_type_find, id3_exts, ID3_CAPS, NULL, NULL);
 11.2637 +  TYPE_FIND_REGISTER (plugin, "application/x-apetag", GST_RANK_PRIMARY + 2,
 11.2638 +      apetag_type_find, apetag_exts, APETAG_CAPS, NULL, NULL);
 11.2639 +  TYPE_FIND_REGISTER (plugin, "audio/x-ttafile", GST_RANK_PRIMARY,
 11.2640 +      tta_type_find, tta_exts, TTA_CAPS, NULL, NULL);
 11.2641 +  TYPE_FIND_REGISTER (plugin, "audio/x-mod", GST_RANK_SECONDARY, mod_type_find,
 11.2642 +      mod_exts, MOD_CAPS, NULL, NULL);
 11.2643 +  TYPE_FIND_REGISTER (plugin, "audio/mpeg", GST_RANK_PRIMARY, mp3_type_find,
 11.2644 +      mp3_exts, MP3_CAPS, NULL, NULL);
 11.2645 +  TYPE_FIND_REGISTER (plugin, "audio/x-ac3", GST_RANK_PRIMARY, ac3_type_find,
 11.2646 +      ac3_exts, AC3_CAPS, NULL, NULL);
 11.2647 +  TYPE_FIND_REGISTER (plugin, "video/mpeg1", GST_RANK_PRIMARY,
 11.2648 +      mpeg1_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL, NULL);
 11.2649 +  TYPE_FIND_REGISTER (plugin, "video/mpeg2", GST_RANK_SECONDARY,
 11.2650 +      mpeg2_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL, NULL);
 11.2651 +  TYPE_FIND_REGISTER (plugin, "video/mpegts", GST_RANK_PRIMARY,
 11.2652 +      mpeg_ts_type_find, mpeg_ts_exts, MPEGTS_CAPS, NULL, NULL);
 11.2653 +  TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY,
 11.2654 +      ogganx_type_find, ogg_exts, OGGANX_CAPS, NULL, NULL);
 11.2655 +  TYPE_FIND_REGISTER (plugin, "video/mpeg", GST_RANK_SECONDARY,
 11.2656 +      mpeg_video_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL, NULL);
 11.2657 +  TYPE_FIND_REGISTER (plugin, "video/mpeg-stream", GST_RANK_MARGINAL,
 11.2658 +      mpeg_video_stream_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL,
 11.2659 +      NULL);
 11.2660 +  TYPE_FIND_REGISTER (plugin, "video/mpeg4", GST_RANK_PRIMARY,
 11.2661 +      mpeg4_video_type_find, m4v_exts, MPEG_VIDEO_CAPS, NULL, NULL);
 11.2662 +  TYPE_FIND_REGISTER (plugin, "video/x-nuv", GST_RANK_SECONDARY,
 11.2663 +      nuv_type_find, nuv_exts, NUV_CAPS, NULL, NULL);
 11.2664 +
 11.2665 +  /* ISO formats */
 11.2666 +  TYPE_FIND_REGISTER (plugin, "audio/x-m4a", GST_RANK_PRIMARY, m4a_type_find,
 11.2667 +      m4a_exts, M4A_CAPS, NULL, NULL);
 11.2668 +  TYPE_FIND_REGISTER (plugin, "application/x-3gp", GST_RANK_PRIMARY,
 11.2669 +      q3gp_type_find, q3gp_exts, Q3GP_CAPS, NULL, NULL);
 11.2670 +  TYPE_FIND_REGISTER (plugin, "video/quicktime", GST_RANK_SECONDARY,
 11.2671 +      qt_type_find, qt_exts, QT_CAPS, NULL, NULL);
 11.2672 +  TYPE_FIND_REGISTER (plugin, "image/x-quicktime", GST_RANK_SECONDARY,
 11.2673 +      qtif_type_find, qtif_exts, QTIF_CAPS, NULL, NULL);
 11.2674 +
 11.2675 +  TYPE_FIND_REGISTER (plugin, "text/html", GST_RANK_SECONDARY, html_type_find,
 11.2676 +      html_exts, HTML_CAPS, NULL, NULL);
 11.2677 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/vnd.rn-realmedia",
 11.2678 +      GST_RANK_SECONDARY, rm_exts, ".RMF", 4, GST_TYPE_FIND_MAXIMUM);
 11.2679 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-pn-realaudio",
 11.2680 +      GST_RANK_SECONDARY, rm_exts, ".ra\375", 4, GST_TYPE_FIND_MAXIMUM);
 11.2681 +  TYPE_FIND_REGISTER (plugin, "application/x-shockwave-flash",
 11.2682 +      GST_RANK_SECONDARY, swf_type_find, swf_exts, SWF_CAPS, NULL, NULL);
 11.2683 +  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-flv", GST_RANK_SECONDARY,
 11.2684 +      flv_exts, "FLV", 3, GST_TYPE_FIND_MAXIMUM);
 11.2685 +  TYPE_FIND_REGISTER (plugin, "text/plain", GST_RANK_MARGINAL, utf8_type_find,
 11.2686 +      utf8_exts, UTF8_CAPS, NULL, NULL);
 11.2687 +  TYPE_FIND_REGISTER (plugin, "text/uri-list", GST_RANK_MARGINAL, uri_type_find,
 11.2688 +      uri_exts, URI_CAPS, NULL, NULL);
 11.2689 +  TYPE_FIND_REGISTER (plugin, "application/smil", GST_RANK_SECONDARY,
 11.2690 +      smil_type_find, smil_exts, SMIL_CAPS, NULL, NULL);
 11.2691 +  TYPE_FIND_REGISTER (plugin, "application/xml", GST_RANK_MARGINAL,
 11.2692 +      xml_type_find, xml_exts, GENERIC_XML_CAPS, NULL, NULL);
 11.2693 +  TYPE_FIND_REGISTER_RIFF (plugin, "audio/x-wav", GST_RANK_PRIMARY, wav_exts,
 11.2694 +      "WAVE");
 11.2695 +  TYPE_FIND_REGISTER (plugin, "audio/x-aiff", GST_RANK_SECONDARY,
 11.2696 +      aiff_type_find, aiff_exts, AIFF_CAPS, NULL, NULL);
 11.2697 +  TYPE_FIND_REGISTER (plugin, "audio/x-svx", GST_RANK_SECONDARY, svx_type_find,
 11.2698 +      svx_exts, SVX_CAPS, NULL, NULL);
 11.2699 +  TYPE_FIND_REGISTER (plugin, "audio/x-paris", GST_RANK_SECONDARY,
 11.2700 +      paris_type_find, paris_exts, PARIS_CAPS, NULL, NULL);
 11.2701 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-nist", GST_RANK_SECONDARY,
 11.2702 +      nist_exts, "NIST", 4, GST_TYPE_FIND_MAXIMUM);
 11.2703 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-voc", GST_RANK_SECONDARY,
 11.2704 +      voc_exts, "Creative", 8, GST_TYPE_FIND_MAXIMUM);
 11.2705 +  TYPE_FIND_REGISTER (plugin, "audio/x-sds", GST_RANK_SECONDARY, sds_type_find,
 11.2706 +      sds_exts, SDS_CAPS, NULL, NULL);
 11.2707 +  TYPE_FIND_REGISTER (plugin, "audio/x-ircam", GST_RANK_SECONDARY,
 11.2708 +      ircam_type_find, ircam_exts, IRCAM_CAPS, NULL, NULL);
 11.2709 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-w64", GST_RANK_SECONDARY,
 11.2710 +      w64_exts, "riff", 4, GST_TYPE_FIND_MAXIMUM);
 11.2711 +  TYPE_FIND_REGISTER (plugin, "audio/x-shorten", GST_RANK_SECONDARY,
 11.2712 +      shn_type_find, shn_exts, SHN_CAPS, NULL, NULL);
 11.2713 +  TYPE_FIND_REGISTER (plugin, "application/x-ape", GST_RANK_SECONDARY,
 11.2714 +      ape_type_find, ape_exts, APE_CAPS, NULL, NULL);
 11.2715 +  TYPE_FIND_REGISTER (plugin, "image/jpeg", GST_RANK_PRIMARY, jpeg_type_find,
 11.2716 +      jpeg_exts, JPEG_CAPS, NULL, NULL);
 11.2717 +  TYPE_FIND_REGISTER_START_WITH (plugin, "image/gif", GST_RANK_PRIMARY,
 11.2718 +      gif_exts, "GIF8", 4, GST_TYPE_FIND_MAXIMUM);
 11.2719 +  TYPE_FIND_REGISTER_START_WITH (plugin, "image/png", GST_RANK_PRIMARY,
 11.2720 +      png_exts, "\211PNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM);
 11.2721 +  TYPE_FIND_REGISTER (plugin, "image/bmp", GST_RANK_PRIMARY, bmp_type_find,
 11.2722 +      bmp_exts, BMP_CAPS, NULL, NULL);
 11.2723 +  TYPE_FIND_REGISTER (plugin, "image/tiff", GST_RANK_PRIMARY, tiff_type_find,
 11.2724 +      tiff_exts, TIFF_CAPS, NULL, NULL);
 11.2725 +  TYPE_FIND_REGISTER (plugin, "video/x-matroska", GST_RANK_PRIMARY,
 11.2726 +      matroska_type_find, matroska_exts, MATROSKA_CAPS, NULL, NULL);
 11.2727 +  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-mve", GST_RANK_SECONDARY,
 11.2728 +      mve_exts, "Interplay MVE File\032\000\032\000\000\001\063\021", 26,
 11.2729 +      GST_TYPE_FIND_MAXIMUM);
 11.2730 +  TYPE_FIND_REGISTER (plugin, "video/x-dv", GST_RANK_SECONDARY, dv_type_find,
 11.2731 +      dv_exts, DV_CAPS, NULL, NULL);
 11.2732 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-amr-nb-sh", GST_RANK_PRIMARY,
 11.2733 +      amr_exts, "#!AMR", 5, GST_TYPE_FIND_LIKELY);
 11.2734 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-amr-wb-sh", GST_RANK_PRIMARY,
 11.2735 +      amr_exts, "#!AMR-WB", 7, GST_TYPE_FIND_MAXIMUM);
 11.2736 +  TYPE_FIND_REGISTER (plugin, "audio/iLBC-sh", GST_RANK_PRIMARY,
 11.2737 +      ilbc_type_find, ilbc_exts, ILBC_CAPS, NULL, NULL);
 11.2738 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-sid", GST_RANK_MARGINAL,
 11.2739 +      sid_exts, "PSID", 4, GST_TYPE_FIND_MAXIMUM);
 11.2740 +  TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-xcf", GST_RANK_SECONDARY,
 11.2741 +      xcf_exts, "gimp xcf", 8, GST_TYPE_FIND_MAXIMUM);
 11.2742 +  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-mng", GST_RANK_SECONDARY,
 11.2743 +      mng_exts, "\212MNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM);
 11.2744 +  TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-jng", GST_RANK_SECONDARY,
 11.2745 +      jng_exts, "\213JNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM);
 11.2746 +  TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-xpixmap", GST_RANK_SECONDARY,
 11.2747 +      xpm_exts, "/* XPM */", 9, GST_TYPE_FIND_MAXIMUM);
 11.2748 +  TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-sun-raster",
 11.2749 +      GST_RANK_SECONDARY, ras_exts, "\131\246\152\225", 4,
 11.2750 +      GST_TYPE_FIND_MAXIMUM);
 11.2751 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-bzip",
 11.2752 +      GST_RANK_SECONDARY, bz2_exts, "BZh", 3, GST_TYPE_FIND_LIKELY);
 11.2753 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-gzip",
 11.2754 +      GST_RANK_SECONDARY, gz_exts, "\037\213", 2, GST_TYPE_FIND_LIKELY);
 11.2755 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/zip", GST_RANK_SECONDARY,
 11.2756 +      zip_exts, "PK\003\004", 4, GST_TYPE_FIND_LIKELY);
 11.2757 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-compress",
 11.2758 +      GST_RANK_SECONDARY, compress_exts, "\037\235", 2, GST_TYPE_FIND_LIKELY);
 11.2759 +  TYPE_FIND_REGISTER (plugin, "audio/x-vorbis", GST_RANK_PRIMARY,
 11.2760 +      vorbis_type_find, NULL, VORBIS_CAPS, NULL, NULL);
 11.2761 +  TYPE_FIND_REGISTER (plugin, "video/x-theora", GST_RANK_PRIMARY,
 11.2762 +      theora_type_find, NULL, THEORA_CAPS, NULL, NULL);
 11.2763 +  TYPE_FIND_REGISTER (plugin, "application/x-ogm-video", GST_RANK_PRIMARY,
 11.2764 +      ogmvideo_type_find, NULL, OGMVIDEO_CAPS, NULL, NULL);
 11.2765 +  TYPE_FIND_REGISTER (plugin, "application/x-ogm-audio", GST_RANK_PRIMARY,
 11.2766 +      ogmaudio_type_find, NULL, OGMAUDIO_CAPS, NULL, NULL);
 11.2767 +  TYPE_FIND_REGISTER (plugin, "application/x-ogm-text", GST_RANK_PRIMARY,
 11.2768 +      ogmtext_type_find, NULL, OGMTEXT_CAPS, NULL, NULL);
 11.2769 +  TYPE_FIND_REGISTER (plugin, "audio/x-speex", GST_RANK_PRIMARY,
 11.2770 +      speex_type_find, NULL, SPEEX_CAPS, NULL, NULL);
 11.2771 +  TYPE_FIND_REGISTER (plugin, "application/x-ogg-skeleton", GST_RANK_PRIMARY,
 11.2772 +      oggskel_type_find, NULL, OGG_SKELETON_CAPS, NULL, NULL);
 11.2773 +  TYPE_FIND_REGISTER (plugin, "text/x-cmml", GST_RANK_PRIMARY, cmml_type_find,
 11.2774 +      NULL, CMML_CAPS, NULL, NULL);
 11.2775 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-executable",
 11.2776 +      GST_RANK_MARGINAL, NULL, "\177ELF", 4, GST_TYPE_FIND_MAXIMUM);
 11.2777 +  TYPE_FIND_REGISTER (plugin, "adts_mpeg_stream", GST_RANK_SECONDARY,
 11.2778 +      aac_type_find, aac_exts, AAC_CAPS, NULL, NULL);
 11.2779 +  TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-spc", GST_RANK_SECONDARY,
 11.2780 +      spc_exts, "SNES-SPC700 Sound File Data", 27, GST_TYPE_FIND_MAXIMUM);
 11.2781 +  TYPE_FIND_REGISTER (plugin, "audio/x-wavpack", GST_RANK_SECONDARY,
 11.2782 +      wavpack_type_find, wavpack_exts, WAVPACK_CAPS, NULL, NULL);
 11.2783 +  TYPE_FIND_REGISTER (plugin, "audio/x-wavpack-correction", GST_RANK_SECONDARY,
 11.2784 +      wavpack_type_find, wavpack_correction_exts, WAVPACK_CORRECTION_CAPS, NULL,
 11.2785 +      NULL);
 11.2786 +  TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-rar",
 11.2787 +      GST_RANK_SECONDARY, rar_exts, "Rar!", 4, GST_TYPE_FIND_LIKELY);
 11.2788 +  TYPE_FIND_REGISTER (plugin, "application/x-tar", GST_RANK_SECONDARY,
 11.2789 +      tar_type_find, tar_exts, TAR_CAPS, NULL, NULL);
 11.2790 +  TYPE_FIND_REGISTER (plugin, "application/x-ar", GST_RANK_SECONDARY,
 11.2791 +      ar_type_find, ar_exts, AR_CAPS, NULL, NULL);
 11.2792 +  TYPE_FIND_REGISTER (plugin, "application/x-ms-dos-executable",
 11.2793 +      GST_RANK_SECONDARY, msdos_type_find, msdos_exts, MSDOS_CAPS, NULL, NULL);
 11.2794 +#if 0
 11.2795 +  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-dirac",
 11.2796 +      GST_RANK_PRIMARY, NULL, "BBCD", 4, GST_TYPE_FIND_MAXIMUM);
 11.2797 +#endif
 11.2798 +  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-dirac",
 11.2799 +      GST_RANK_PRIMARY, NULL, "KW-DIRAC", 8, GST_TYPE_FIND_MAXIMUM);
 11.2800 +  TYPE_FIND_REGISTER (plugin, "multipart/x-mixed-replace", GST_RANK_SECONDARY,
 11.2801 +      multipart_type_find, NULL, MULTIPART_CAPS, NULL, NULL);
 11.2802 +  TYPE_FIND_REGISTER (plugin, "application/x-mmsh", GST_RANK_SECONDARY,
 11.2803 +      mmsh_type_find, NULL, MMSH_CAPS, NULL, NULL);
 11.2804 +  return TRUE;
 11.2805 +}
 11.2806 +
 11.2807 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
 11.2808 +    GST_VERSION_MINOR,
 11.2809 +    "typefindfunctions",
 11.2810 +    "default typefind functions",
 11.2811 +    plugin_init, VERSION, "LGPL", "GStreamer Base Plug-ins CVS/prerelease", "Gstreamer CVS")