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")