1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/gst-gmyth/nuvdemux/gstnuvdemux.c Tue May 01 16:04:02 2007 +0100
1.3 @@ -0,0 +1,1677 @@
1.4 +/* GStreamer
1.5 + * Copyright (C) <2006> Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
1.6 + * Rosfran Borges <rosfran.borges@indt.org.br>
1.7 + *
1.8 + * This library is free software; you can redistribute it and/or
1.9 + * modify it under the terms of the GNU Library General Public
1.10 + * License as published by the Free Software Foundation; either
1.11 + * version 2 of the License, or (at your option) any later version.
1.12 + *
1.13 + * This library is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.16 + * Library General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU Library General Public
1.19 + * License along with this library; if not, write to the
1.20 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1.21 + * Boston, MA 02111-1307, USA.
1.22 + */
1.23 +/* Element-Checklist-Version: 5 */
1.24 +
1.25 +/**
1.26 + * SECTION:element-nuvdemux
1.27 + *
1.28 + * <refsect2>
1.29 + * <para>
1.30 + * Demuxes an .nuv file into raw or compressed audio and/or video streams.
1.31 + * </para>
1.32 + * <para>
1.33 + * This element currently only supports pull-based scheduling.
1.34 + * </para>
1.35 + * <title>Example launch line</title>
1.36 + * <para>
1.37 + * <programlisting>
1.38 + * gst-launch filesrc test.nuv ! nuvdemux name=demux demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
1.39 + * </programlisting>
1.40 + * Play (parse and decode) an .nuv file and try to output it to
1.41 + * an automatically detected soundcard and videosink. If the NUV file contains
1.42 + * compressed audio or video data, this will only work if you have the
1.43 + * right decoder elements/plugins installed.
1.44 + * </para>
1.45 + * </refsect2>
1.46 + *
1.47 + */
1.48 +
1.49 +#ifdef HAVE_CONFIG_H
1.50 +#include "config.h"
1.51 +#endif
1.52 +
1.53 +#include <gst/gst.h>
1.54 +#include <gst/gsterror.h>
1.55 +#include <gst/gstplugin.h>
1.56 +#include <string.h>
1.57 +#include <math.h>
1.58 +
1.59 +#include "glib/gi18n.h"
1.60 +#include "gstnuvdemux.h"
1.61 +
1.62 +#define GST_NUV_DEMUX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_NUV_DEMUX, GstNuvDemuxPrivate))
1.63 +
1.64 +GST_DEBUG_CATEGORY_STATIC (nuvdemux_debug);
1.65 +#define GST_CAT_DEFAULT nuvdemux_debug
1.66 +#define GST_FLOW_ERROR_NO_DATA -101
1.67 +#define GST_FLOW_ERROR_EOS -102
1.68 +
1.69 +enum
1.70 +{
1.71 + NUV_PUSH_MODE = 0,
1.72 + NUV_PULL_MODE
1.73 +};
1.74 +
1.75 +GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT);
1.76 +
1.77 +static const GstElementDetails gst_nuv_demux_details =
1.78 +GST_ELEMENT_DETAILS ("Nuv demuxer",
1.79 + "Codec/Demuxer",
1.80 + "Demultiplex a .nuv file into audio and video",
1.81 + "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
1.82 + "Rosfran Borges <rosfran.borges@indt.org.br>");
1.83 +
1.84 +
1.85 +/* file header */
1.86 +typedef struct
1.87 +{
1.88 + gchar id[12]; /* "NuppelVideo\0" or "MythTVVideo\0" */
1.89 + gchar version[5]; /* "x.xx\0" */
1.90 +
1.91 + gint i_width;
1.92 + gint i_height;
1.93 + gint i_width_desired;
1.94 + gint i_height_desired;
1.95 +
1.96 + gchar i_mode; /* P progressive, I interlaced */
1.97 +
1.98 + gdouble d_aspect; /* 1.0 squared pixel */
1.99 + gdouble d_fps;
1.100 + //fps num/denom
1.101 + gint i_fpsn;
1.102 + gint i_fpsd;
1.103 +
1.104 + gint i_video_blocks; /* 0 no video, -1 unknown */
1.105 + gint i_audio_blocks;
1.106 + gint i_text_blocks;
1.107 +
1.108 + gint i_keyframe_distance;
1.109 +
1.110 +} nuv_header;
1.111 +
1.112 +/* frame header */
1.113 +typedef struct
1.114 +{
1.115 + gchar i_type; /* A: audio, V: video, S: sync; T: test
1.116 + R: Seekpoint (string:RTjjjjjjjj)
1.117 + D: Extra data for codec */
1.118 + gchar i_compression; /* V: 0 uncompressed
1.119 + 1 RTJpeg
1.120 + 2 RTJpeg+lzo
1.121 + N black frame
1.122 + L copy last
1.123 + A: 0 uncompressed (44100 1-bits, 2ch)
1.124 + 1 lzo
1.125 + 2 layer 2
1.126 + 3 layer 3
1.127 + F flac
1.128 + S shorten
1.129 + N null frame loudless
1.130 + L copy last
1.131 + S: B audio and vdeo sync point
1.132 + A audio sync info (timecode == effective
1.133 + dsp frequency*100)
1.134 + V next video sync (timecode == next video
1.135 + frame num)
1.136 + S audio,video,text correlation */
1.137 + gchar i_keyframe; /* 0 keyframe, else no no key frame */
1.138 + guint8 i_filters; /* 0x01: gauss 5 pixel (8,2,2,2,2)/16
1.139 + 0x02: gauss 5 pixel (8,1,1,1,1)/12
1.140 + 0x04: cartoon filter */
1.141 +
1.142 + gint32 i_timecode; /* ms */
1.143 +
1.144 + gint i_length; /* V,A,T: length of following data
1.145 + S: length of packet correl */
1.146 +} nuv_frame_header;
1.147 +
1.148 +
1.149 +/* FIXME Not sure of this one */
1.150 +typedef struct
1.151 +{
1.152 + gint i_version;
1.153 + guint32 i_video_fcc;
1.154 +
1.155 + guint32 i_audio_fcc;
1.156 + gint i_audio_sample_rate;
1.157 + gint i_audio_bits_per_sample;
1.158 + gint i_audio_channels;
1.159 + gint i_audio_compression_ratio;
1.160 + gint i_audio_quality;
1.161 + gint i_rtjpeg_quality;
1.162 + gint i_rtjpeg_luma_filter;
1.163 + gint i_rtjpeg_chroma_filter;
1.164 + gint i_lavc_bitrate;
1.165 + gint i_lavc_qmin;
1.166 + gint i_lavc_qmax;
1.167 + gint i_lavc_maxqdiff;
1.168 + gint64 i_seekable_offset;
1.169 + gint64 i_keyframe_adjust_offset;
1.170 +
1.171 +} nuv_extended_header;
1.172 +
1.173 +typedef struct
1.174 +{
1.175 + gint64 timecode;
1.176 + gint64 offset;
1.177 +
1.178 +} frame_index_data;
1.179 +
1.180 +typedef enum {
1.181 + GST_NUV_DEMUX_START,
1.182 + GST_NUV_DEMUX_HEADER_DATA,
1.183 + GST_NUV_DEMUX_EXTRA_DATA,
1.184 + GST_NUV_DEMUX_MPEG_DATA,
1.185 + GST_NUV_DEMUX_EXTEND_HEADER,
1.186 + GST_NUV_DEMUX_EXTEND_HEADER_DATA,
1.187 + GST_NUV_DEMUX_INDEX_CREATE,
1.188 + GST_NUV_DEMUX_FRAME_HEADER,
1.189 + GST_NUV_DEMUX_MOVI,
1.190 + GST_NUV_DEMUX_INVALID_DATA
1.191 +} GstNuvDemuxState;
1.192 +
1.193 +struct _GstNuvDemuxPrivate {
1.194 + /* used for indicate the mode */
1.195 + guint mode;
1.196 +
1.197 + /* used on push mode */
1.198 + GstAdapter *adapter;
1.199 +
1.200 + /* pads */
1.201 + GstPad *sinkpad;
1.202 + GstPad *src_video_pad;
1.203 + GstPad *src_audio_pad;
1.204 +
1.205 + /* Flow control */
1.206 + GstFlowReturn last_video_return;
1.207 + GstFlowReturn last_audio_return;
1.208 + gboolean more_data;
1.209 + gboolean eos;
1.210 +
1.211 + /* NUV decoding state */
1.212 + GstNuvDemuxState state;
1.213 + guint64 offset;
1.214 +
1.215 + /* duration information */
1.216 + guint64 duration_bytes;
1.217 + guint64 duration_time;
1.218 + guint64 segment_stop;
1.219 + guint64 segment_start;
1.220 +
1.221 + /* segment control info */
1.222 + gboolean new_audio_segment;
1.223 + gboolean new_video_segment;
1.224 +
1.225 + /* Mpeg ExtraData */
1.226 + guint64 mpeg_data_size;
1.227 + GstBuffer *mpeg_buffer;
1.228 +
1.229 + /* Headers */
1.230 + nuv_header h;
1.231 + nuv_extended_header eh;
1.232 + nuv_frame_header fh;
1.233 +
1.234 + /* anothers info */
1.235 + guint64 header_lengh;
1.236 + gint64 time_start;
1.237 + gint64 time_diff;
1.238 + gint64 time_qos;
1.239 + guint64 last_frame_time;
1.240 + GSList *index;
1.241 +};
1.242 +
1.243 +
1.244 +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
1.245 + GST_PAD_SINK,
1.246 + GST_PAD_ALWAYS,
1.247 + GST_STATIC_CAPS ("video/x-nuv"));
1.248 +
1.249 +static GstStaticPadTemplate audio_src_template =
1.250 +GST_STATIC_PAD_TEMPLATE ("audio_src",
1.251 + GST_PAD_SRC,
1.252 + GST_PAD_SOMETIMES,
1.253 + GST_STATIC_CAPS_ANY);
1.254 +
1.255 +static GstStaticPadTemplate video_src_template =
1.256 +GST_STATIC_PAD_TEMPLATE ("video_src",
1.257 + GST_PAD_SRC,
1.258 + GST_PAD_SOMETIMES,
1.259 + GST_STATIC_CAPS_ANY);
1.260 +
1.261 +static void gst_nuv_demux_dispose (GObject * object);
1.262 +static void gst_nuv_demux_finalize (GObject * object);
1.263 +static GstStateChangeReturn gst_nuv_demux_change_state (GstElement * element,
1.264 + GstStateChange transition);
1.265 +static void gst_nuv_demux_loop (GstPad * pad);
1.266 +static GstFlowReturn gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf);
1.267 +static GstFlowReturn gst_nuv_demux_play (GstPad * pad);
1.268 +static gboolean gst_nuv_demux_sink_activate_pull (GstPad * sinkpad,
1.269 + gboolean active);
1.270 +static gboolean gst_nuv_demux_sink_activate_push (GstPad * pad,
1.271 + gboolean active);
1.272 +static gboolean gst_nuv_demux_sink_activate (GstPad * sinkpad);
1.273 +//static gboolean gst_nuv_demux_sink_event (GstPad *pad, GstEvent *event);
1.274 +static gboolean gst_nuv_demux_srcpad_event (GstPad * pad, GstEvent * event);
1.275 +static frame_index_data * gst_nuv_demux_do_seek_index (GstNuvDemux *nuv, gint64 seek_pos,
1.276 + gint64 segment_stop, GstFormat format);
1.277 +
1.278 +
1.279 +
1.280 +static GstFlowReturn gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size,
1.281 + gboolean move, GstBuffer ** buffer);
1.282 +static void gst_nuv_demux_reset (GstNuvDemux * nuv);
1.283 +static void gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv);
1.284 +static void gst_nuv_demux_send_eos (GstNuvDemux * nuv);
1.285 +static void gst_nuv_demux_create_seek_index (GstNuvDemux * nuv);
1.286 +
1.287 +
1.288 +#if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
1.289 +GstBuffer * gst_adapter_take_buffer (GstAdapter * adapter, guint nbytes);
1.290 +#endif
1.291 +
1.292 +
1.293 +GST_BOILERPLATE (GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
1.294 +
1.295 +/******************************************************************************
1.296 + * Utils function
1.297 + ******************************************************************************/
1.298 +#if G_BYTE_ORDER == G_BIG_ENDIAN
1.299 +static inline gdouble
1.300 +_gdouble_swap_le_be (gdouble * d)
1.301 +{
1.302 + union
1.303 + {
1.304 + guint64 i;
1.305 + gdouble d;
1.306 + } u;
1.307 +
1.308 + u.d = *d;
1.309 + u.i = GUINT64_SWAP_LE_BE (u.i);
1.310 + return u.d;
1.311 +}
1.312 +
1.313 +#define READ_DOUBLE_FROM_LE(d) (_gdouble_swap_le_be((gdouble* ) d))
1.314 +#else /* G_BYTE_ORDER != G_BIG_ENDIAN */
1.315 +#define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
1.316 +#endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
1.317 +
1.318 +static void
1.319 +double2fraction (double in, int *num, int *denom)
1.320 +{
1.321 + if (in == 29.97) {
1.322 + *num = 30000;
1.323 + *denom = 1001;
1.324 + } else if (in == 23.976) {
1.325 + *num = 24000;
1.326 + *denom = 1001;
1.327 + } else {
1.328 + *denom = 1;
1.329 + while (in - floor(in) >= 0.1) {
1.330 + *denom *= 10;
1.331 + in *= 10.0;
1.332 + }
1.333 + *num = (int)floor(in);
1.334 + }
1.335 +}
1.336 +
1.337 +/* GObject Functions */
1.338 +
1.339 +static void
1.340 +gst_nuv_demux_base_init (gpointer klass)
1.341 +{
1.342 + GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1.343 +
1.344 + gst_element_class_add_pad_template (element_class,
1.345 + gst_static_pad_template_get (&audio_src_template));
1.346 +
1.347 + gst_element_class_add_pad_template (element_class,
1.348 + gst_static_pad_template_get (&video_src_template));
1.349 +
1.350 + gst_element_class_add_pad_template (element_class,
1.351 + gst_static_pad_template_get (&sink_template));
1.352 + gst_element_class_set_details (element_class, &gst_nuv_demux_details);
1.353 +}
1.354 +
1.355 +static void
1.356 +gst_nuv_demux_class_init (GstNuvDemuxClass * klass)
1.357 +{
1.358 + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1.359 + GObjectClass *gobject_class = (GObjectClass *) klass;
1.360 +
1.361 + GST_DEBUG_CATEGORY_INIT (nuvdemux_debug, "nuvdemux",
1.362 + 0, "Demuxer for NUV streams");
1.363 +
1.364 + parent_class = g_type_class_peek_parent (klass);
1.365 +
1.366 + gobject_class->dispose = gst_nuv_demux_dispose;
1.367 + gobject_class->finalize = gst_nuv_demux_finalize;
1.368 + gstelement_class->change_state = gst_nuv_demux_change_state;
1.369 +
1.370 + g_type_class_add_private (gobject_class, sizeof (GstNuvDemuxPrivate));
1.371 +}
1.372 +
1.373 +static void
1.374 +gst_nuv_demux_init (GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
1.375 +{
1.376 + nuv->priv = GST_NUV_DEMUX_GET_PRIVATE (nuv);
1.377 + nuv->priv->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
1.378 +
1.379 + /* creating adapter */
1.380 + nuv->priv->mode = NUV_PUSH_MODE;
1.381 + nuv->priv->adapter = gst_adapter_new ();
1.382 +
1.383 + nuv->priv->new_audio_segment = TRUE;
1.384 + nuv->priv->new_video_segment = TRUE;
1.385 +
1.386 + gst_pad_set_activate_function (nuv->priv->sinkpad, gst_nuv_demux_sink_activate);
1.387 + gst_pad_set_activatepull_function (nuv->priv->sinkpad,
1.388 + gst_nuv_demux_sink_activate_pull);
1.389 + gst_pad_set_activatepush_function (nuv->priv->sinkpad,
1.390 + gst_nuv_demux_sink_activate_push);
1.391 + gst_pad_set_chain_function (nuv->priv->sinkpad,
1.392 + GST_DEBUG_FUNCPTR (gst_nuv_demux_chain));
1.393 +/*
1.394 + gst_pad_set_event_function (nuv->priv->sinkpad,
1.395 + gst_nuv_demux_sink_event);
1.396 +*/
1.397 +
1.398 + gst_element_add_pad (GST_ELEMENT (nuv), nuv->priv->sinkpad);
1.399 +
1.400 +}
1.401 +
1.402 +static void
1.403 +gst_nuv_demux_dispose (GObject * object)
1.404 +{
1.405 + GstNuvDemux *nuv = GST_NUV_DEMUX (object);
1.406 +
1.407 +
1.408 + if (nuv->priv->mpeg_buffer != NULL) {
1.409 + gst_buffer_unref (nuv->priv->mpeg_buffer);
1.410 + }
1.411 +
1.412 + gst_nuv_demux_reset (GST_NUV_DEMUX (object));
1.413 + gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (object));
1.414 +
1.415 + if (nuv->priv->adapter != NULL) {
1.416 + gst_object_unref (nuv->priv->adapter);
1.417 + }
1.418 +}
1.419 +
1.420 +static void
1.421 +gst_nuv_demux_finalize (GObject * object)
1.422 +{
1.423 + G_OBJECT_CLASS (parent_class)->finalize (object);
1.424 +}
1.425 +
1.426 +
1.427 +/* HeaderLoad:
1.428 + */
1.429 +static GstFlowReturn
1.430 +gst_nuv_demux_header_load (GstNuvDemux * nuv, nuv_header *h)
1.431 +{
1.432 + GstBuffer *buffer = NULL;
1.433 + GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 72, TRUE, &buffer);
1.434 +
1.435 + if ((res != GST_FLOW_OK) || (buffer == NULL)) {
1.436 + goto done;
1.437 + }
1.438 +
1.439 + memcpy (h->id, buffer->data, 12);
1.440 + memcpy (h->version, buffer->data + 12, 5);
1.441 + h->i_width = GST_READ_UINT32_LE (&buffer->data[20]);
1.442 + h->i_height = GST_READ_UINT32_LE (&buffer->data[24]);
1.443 + h->i_width_desired = GST_READ_UINT32_LE (&buffer->data[28]);
1.444 + h->i_height_desired = GST_READ_UINT32_LE (&buffer->data[32]);
1.445 + h->i_mode = GPOINTER_TO_INT (buffer->data[36]);
1.446 + h->d_aspect = READ_DOUBLE_FROM_LE (&buffer->data[40]);
1.447 + h->d_fps = READ_DOUBLE_FROM_LE (&buffer->data[48]);
1.448 + /* get the num and denom values from fps */
1.449 + double2fraction (h->d_fps, &h->i_fpsn, &h->i_fpsd);
1.450 + h->i_video_blocks = GST_READ_UINT32_LE (&buffer->data[56]);
1.451 + h->i_audio_blocks = GST_READ_UINT32_LE (&buffer->data[60]);
1.452 + h->i_text_blocks = GST_READ_UINT32_LE (&buffer->data[64]);
1.453 + h->i_keyframe_distance = GST_READ_UINT32_LE (&buffer->data[68]);
1.454 +
1.455 + GST_DEBUG_OBJECT (nuv,
1.456 + "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d", h->id,
1.457 + h->version, h->i_width, h->i_height, h->d_aspect, h->d_fps,
1.458 + h->i_video_blocks, h->i_audio_blocks, h->i_text_blocks,
1.459 + h->i_keyframe_distance);
1.460 +
1.461 +done:
1.462 + if (buffer != NULL) {
1.463 + gst_buffer_unref (buffer);
1.464 + buffer = NULL;
1.465 + }
1.466 + return res;
1.467 +}
1.468 +
1.469 +static GstFlowReturn
1.470 +gst_nuv_demux_stream_header_data (GstNuvDemux * nuv)
1.471 +{
1.472 + GstFlowReturn res;
1.473 +
1.474 + res = gst_nuv_demux_header_load (nuv, &nuv->priv->h);
1.475 + if (res == GST_FLOW_OK)
1.476 + nuv->priv->state = GST_NUV_DEMUX_EXTRA_DATA;
1.477 + return res;
1.478 +}
1.479 +
1.480 +/*
1.481 + * Read NUV file tag
1.482 + */
1.483 +static GstFlowReturn
1.484 +gst_nuv_demux_stream_file_header (GstNuvDemux * nuv)
1.485 +{
1.486 + GstFlowReturn res = GST_FLOW_OK;
1.487 + GstBuffer *file_header = NULL;
1.488 +
1.489 + res = gst_nuv_demux_read_bytes (nuv, 12, FALSE, &file_header);
1.490 + if (res == GST_FLOW_OK) {
1.491 + if (strncmp ((gchar *) file_header->data, "MythTVVideo", 11) ||
1.492 + strncmp ((gchar *) file_header->data, "NuppelVideo", 11)) {
1.493 + nuv->priv->state = GST_NUV_DEMUX_HEADER_DATA;
1.494 + } else {
1.495 + GST_DEBUG_OBJECT (nuv, "error parsing file header");
1.496 + nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
1.497 + res = GST_FLOW_ERROR;
1.498 + }
1.499 + }
1.500 +
1.501 + if (file_header != NULL) {
1.502 + gst_buffer_unref (file_header);
1.503 + file_header = NULL;
1.504 + }
1.505 + return res;
1.506 +}
1.507 +
1.508 +/* FrameHeaderLoad:
1.509 + */
1.510 +static GstFlowReturn
1.511 +gst_nuv_demux_frame_header_load (GstNuvDemux * nuv, nuv_frame_header *h)
1.512 +{
1.513 + unsigned char *data;
1.514 + GstBuffer *buf = NULL;
1.515 +
1.516 + GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 12, TRUE, &buf);
1.517 +
1.518 + if ((res != GST_FLOW_OK) || (buf == NULL)) {
1.519 + goto done;
1.520 + }
1.521 +
1.522 + data = buf->data;
1.523 +
1.524 + h->i_type = GPOINTER_TO_INT (data[0]);
1.525 + h->i_compression = GPOINTER_TO_INT (data[1]);
1.526 + h->i_keyframe = GPOINTER_TO_INT (data[2]);
1.527 + h->i_filters = GPOINTER_TO_INT (data[3]);
1.528 + h->i_timecode = GST_READ_UINT32_LE (&data[4]);
1.529 + h->i_length = GST_READ_UINT32_LE (&data[8]);
1.530 +
1.531 + GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
1.532 + h->i_type,
1.533 + h->i_compression ? h->i_compression : ' ',
1.534 + h->i_keyframe ? h->i_keyframe : ' ',
1.535 + h->i_filters, h->i_timecode, h->i_length);
1.536 +
1.537 +done:
1.538 + if (buf != NULL) {
1.539 + gst_buffer_unref (buf);
1.540 + buf = NULL;
1.541 + }
1.542 +
1.543 + return res;
1.544 +}
1.545 +
1.546 +static GstFlowReturn
1.547 +gst_nuv_demux_extended_header_load (GstNuvDemux * nuv,
1.548 + nuv_extended_header * h)
1.549 +{
1.550 + unsigned char *data;
1.551 + GstBuffer *buff = NULL;
1.552 +
1.553 + GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 512, TRUE, &buff);
1.554 +
1.555 + if ((res != GST_FLOW_OK) || (buff == NULL)) {
1.556 + goto done;
1.557 + }
1.558 +
1.559 + data = buff->data;
1.560 + h->i_version = GST_READ_UINT32_LE (&data[0]);
1.561 + h->i_video_fcc = GST_MAKE_FOURCC (data[4], data[5], data[6], data[7]);
1.562 + h->i_audio_fcc = GST_MAKE_FOURCC (data[8], data[9], data[10], data[11]);
1.563 + h->i_audio_sample_rate = GST_READ_UINT32_LE (&data[12]);
1.564 + h->i_audio_bits_per_sample = GST_READ_UINT32_LE (&data[16]);
1.565 + h->i_audio_channels = GST_READ_UINT32_LE (&data[20]);
1.566 + h->i_audio_compression_ratio = GST_READ_UINT32_LE (&data[24]);
1.567 + h->i_audio_quality = GST_READ_UINT32_LE (&data[28]);
1.568 + h->i_rtjpeg_quality = GST_READ_UINT32_LE (&data[32]);
1.569 + h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE (&data[36]);
1.570 + h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE (&data[40]);
1.571 + h->i_lavc_bitrate = GST_READ_UINT32_LE (&data[44]);
1.572 + h->i_lavc_qmin = GST_READ_UINT32_LE (&data[48]);
1.573 + h->i_lavc_qmin = GST_READ_UINT32_LE (&data[52]);
1.574 + h->i_lavc_maxqdiff = GST_READ_UINT32_LE (&data[56]);
1.575 + h->i_seekable_offset = GST_READ_UINT64_LE (&data[60]);
1.576 + h->i_keyframe_adjust_offset = GST_READ_UINT64_LE (&data[68]);
1.577 +
1.578 + GST_DEBUG_OBJECT (nuv,
1.579 + "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d"
1.580 + "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld",
1.581 + h->i_version, (gchar *) & h->i_video_fcc, (gchar *) & h->i_audio_fcc,
1.582 + h->i_audio_sample_rate, h->i_audio_bits_per_sample, h->i_audio_channels,
1.583 + h->i_audio_compression_ratio, h->i_audio_quality, h->i_rtjpeg_quality,
1.584 + h->i_rtjpeg_luma_filter, h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate,
1.585 + h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff, h->i_seekable_offset,
1.586 + h->i_keyframe_adjust_offset);
1.587 +
1.588 +done:
1.589 + if (buff != NULL) {
1.590 + gst_buffer_unref (buff);
1.591 + buff = NULL;
1.592 + }
1.593 + return res;
1.594 +}
1.595 +
1.596 +
1.597 +/* Query Functions */
1.598 +static const GstQueryType *
1.599 +gst_nuv_demux_get_src_query_types (GstPad * pad)
1.600 +{
1.601 + static const GstQueryType src_types[] = {
1.602 + GST_QUERY_POSITION,
1.603 + GST_QUERY_DURATION,
1.604 + 0
1.605 + };
1.606 +
1.607 + return src_types;
1.608 +}
1.609 +
1.610 +static gboolean
1.611 +gst_nuv_demux_handle_src_query (GstPad * pad, GstQuery * query)
1.612 +{
1.613 + gboolean res = FALSE;
1.614 + GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
1.615 +
1.616 + switch (GST_QUERY_TYPE (query)) {
1.617 + case GST_QUERY_POSITION:
1.618 + if (GST_CLOCK_TIME_IS_VALID (nuv->priv->last_frame_time)) {
1.619 + gst_query_set_position (query, GST_FORMAT_TIME, nuv->priv->last_frame_time);
1.620 + res = TRUE;
1.621 + }
1.622 + break;
1.623 + case GST_QUERY_DURATION:
1.624 + {
1.625 + if (nuv->priv->duration_time != GST_CLOCK_TIME_NONE) {
1.626 + gst_query_set_duration (query, GST_FORMAT_TIME, nuv->priv->duration_time);
1.627 + res = TRUE;
1.628 + }
1.629 + }
1.630 + break;
1.631 + default:
1.632 + res = FALSE;
1.633 + break;
1.634 + }
1.635 +
1.636 + gst_object_unref (nuv);
1.637 +
1.638 + return res;
1.639 +}
1.640 +
1.641 +static GstPad*
1.642 +gst_nuv_demux_create_pad (GstNuvDemux *nuv, GstCaps *caps, GstStaticPadTemplate *template, const gchar* name)
1.643 +{
1.644 + GstPad *pad = NULL;
1.645 + pad = gst_pad_new_from_static_template (template, name);
1.646 + gst_pad_set_caps (pad, caps);
1.647 + gst_pad_set_active (pad, TRUE);
1.648 + gst_pad_use_fixed_caps (pad);
1.649 + gst_element_add_pad (GST_ELEMENT (nuv), pad);
1.650 +
1.651 + gst_pad_set_event_function (pad,
1.652 + GST_DEBUG_FUNCPTR (gst_nuv_demux_srcpad_event));
1.653 +
1.654 + gst_pad_set_query_type_function (pad,
1.655 + GST_DEBUG_FUNCPTR (gst_nuv_demux_get_src_query_types));
1.656 +
1.657 + gst_pad_set_query_function (pad,
1.658 + GST_DEBUG_FUNCPTR (gst_nuv_demux_handle_src_query));
1.659 +
1.660 +
1.661 + return pad;
1.662 +}
1.663 +
1.664 +static void
1.665 +gst_nuv_demux_create_pads (GstNuvDemux * nuv)
1.666 +{
1.667 + if (nuv->priv->h.i_video_blocks != 0) {
1.668 + GstCaps *video_caps = NULL;
1.669 +
1.670 + video_caps = gst_caps_new_simple ("video/x-divx",
1.671 + "divxversion", G_TYPE_INT, 4,
1.672 + "width", G_TYPE_INT, nuv->priv->h.i_width,
1.673 + "height", G_TYPE_INT, nuv->priv->h.i_height,
1.674 + "framerate", GST_TYPE_FRACTION, nuv->priv->h.i_fpsn, nuv->priv->h.i_fpsd,
1.675 + "format", GST_TYPE_FOURCC, nuv->priv->eh.i_video_fcc,
1.676 + "pixel-aspect-ratio", GST_TYPE_FRACTION,
1.677 + (gint) (nuv->priv->h.d_aspect * 1000.0f), 1000, NULL);
1.678 +
1.679 + nuv->priv->src_video_pad = gst_nuv_demux_create_pad (nuv, video_caps, &video_src_template, "video_src");
1.680 + gst_caps_unref (video_caps);
1.681 + }
1.682 +
1.683 + if (nuv->priv->h.i_audio_blocks != 0) {
1.684 + GstCaps *audio_caps = NULL;
1.685 +
1.686 + audio_caps = gst_caps_new_simple ("audio/mpeg",
1.687 + "rate", G_TYPE_INT, nuv->priv->eh.i_audio_sample_rate,
1.688 + "format", GST_TYPE_FOURCC, nuv->priv->eh.i_audio_fcc,
1.689 + "channels", G_TYPE_INT, nuv->priv->eh.i_audio_channels,
1.690 + "layer", G_TYPE_INT, 3, // fixme: magic number
1.691 + "mpegversion", G_TYPE_INT, nuv->priv->eh.i_version, NULL);
1.692 +
1.693 + nuv->priv->src_audio_pad = gst_nuv_demux_create_pad (nuv, audio_caps, &audio_src_template, "audio_src");
1.694 + gst_caps_unref (audio_caps);
1.695 + }
1.696 +
1.697 + gst_element_no_more_pads (GST_ELEMENT (nuv));
1.698 +}
1.699 +
1.700 +static gboolean
1.701 +gst_nuv_demux_validate_header (nuv_frame_header *h)
1.702 +{
1.703 + gboolean valid = FALSE;
1.704 + //g_usleep (1 * G_USEC_PER_SEC );
1.705 + switch (h->i_type) {
1.706 +/*
1.707 + case 'V':
1.708 + if (h->i_compression == 0 ||
1.709 + h->i_compression == 1 ||
1.710 + h->i_compression == 2 ||
1.711 + h->i_compression == 'N' ||
1.712 + h->i_compression == 'L') {
1.713 + valid = TRUE;
1.714 + }
1.715 + break;
1.716 + case 'A':
1.717 + if (h->i_compression == 0 ||
1.718 + h->i_compression == 1 ||
1.719 + h->i_compression == 2 ||
1.720 + h->i_compression == 3 ||
1.721 + h->i_compression == 'F' ||
1.722 + h->i_compression == 'S' ||
1.723 + h->i_compression == 'N' ||
1.724 + h->i_compression == 'L') {
1.725 + valid = TRUE;
1.726 + }
1.727 + break;
1.728 + case 'S':
1.729 + if (h->i_compression == 'B' ||
1.730 + h->i_compression == 'A' ||
1.731 + h->i_compression == 'V' ||
1.732 + h->i_compression == 'S') {
1.733 + valid = TRUE;
1.734 + }
1.735 + break;
1.736 +*/
1.737 + case 'A':
1.738 + case 'V':
1.739 + case 'S':
1.740 + case 'R':
1.741 + case 'D':
1.742 + case 'Q':
1.743 + valid = TRUE;
1.744 + break;
1.745 + default:
1.746 + valid = FALSE;
1.747 + }
1.748 +
1.749 + return valid;
1.750 +}
1.751 +
1.752 +static GstFlowReturn
1.753 +gst_nuv_demux_read_head_frame (GstNuvDemux * nuv)
1.754 +{
1.755 + GstFlowReturn ret = GST_FLOW_OK;
1.756 + gboolean valid = FALSE;
1.757 +
1.758 + do {
1.759 + ret = gst_nuv_demux_frame_header_load (nuv, &nuv->priv->fh);
1.760 + if (ret != GST_FLOW_OK) {
1.761 + return ret;
1.762 + }
1.763 +
1.764 + if (gst_nuv_demux_validate_header (&nuv->priv->fh) == TRUE)
1.765 + valid = TRUE;
1.766 +
1.767 + } while (valid == FALSE);
1.768 +
1.769 + nuv->priv->state = GST_NUV_DEMUX_MOVI;
1.770 + return ret;
1.771 +}
1.772 +
1.773 +static gboolean
1.774 +gst_nuv_combine_flow (GstNuvDemux *nuv)
1.775 +{
1.776 + GstFlowReturn ret_video = nuv->priv->last_video_return;
1.777 + GstFlowReturn ret_audio = nuv->priv->last_audio_return;
1.778 +
1.779 + if ((ret_video != GST_FLOW_OK) &&
1.780 + (ret_audio != GST_FLOW_OK))
1.781 + return FALSE;
1.782 +
1.783 + if (GST_FLOW_IS_FATAL (ret_video))
1.784 + return FALSE;
1.785 +
1.786 + if (GST_FLOW_IS_FATAL (ret_audio))
1.787 + return FALSE;
1.788 +
1.789 + return TRUE;
1.790 +}
1.791 +
1.792 +static GstFlowReturn
1.793 +gst_nuv_demux_stream_data (GstNuvDemux * nuv)
1.794 +{
1.795 + GstFlowReturn ret = GST_FLOW_OK;
1.796 + GstPad *pad = NULL;
1.797 + guint64 timestamp;
1.798 + GstBuffer *buf = NULL;
1.799 + nuv_frame_header h;
1.800 +
1.801 + h = nuv->priv->fh;
1.802 +
1.803 + if (h.i_type == 'R') {
1.804 + goto done;
1.805 + }
1.806 +
1.807 + if (h.i_length > 0) {
1.808 + ret = gst_nuv_demux_read_bytes (nuv, h.i_length, TRUE, &buf);
1.809 + if ((ret != GST_FLOW_OK) || (buf == NULL)) {
1.810 + goto done;
1.811 + }
1.812 +
1.813 + if ((h.i_timecode < 0)) {
1.814 + h.i_timecode = 0;
1.815 + //goto done;
1.816 + }
1.817 +
1.818 + timestamp = h.i_timecode * GST_MSECOND;
1.819 + GST_BUFFER_TIMESTAMP (buf) = timestamp;
1.820 + }
1.821 + else {
1.822 + goto done;
1.823 + }
1.824 +
1.825 +
1.826 + switch (h.i_type) {
1.827 + case 'V':
1.828 + {
1.829 + pad = nuv->priv->src_video_pad;
1.830 +
1.831 + if (nuv->priv->new_video_segment) {
1.832 +
1.833 + /* send new segment event*/
1.834 + gst_pad_push_event (nuv->priv->src_video_pad,
1.835 + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0,
1.836 + GST_CLOCK_TIME_NONE, 0));
1.837 +
1.838 + if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
1.839 + nuv->priv->time_start = timestamp;
1.840 + }
1.841 + nuv->priv->new_video_segment = FALSE;
1.842 + }
1.843 +
1.844 + break;
1.845 + }
1.846 + case 'A':
1.847 + {
1.848 + pad = nuv->priv->src_audio_pad;
1.849 +
1.850 + if (nuv->priv->new_audio_segment) {
1.851 + /* send new segment event*/
1.852 + gst_pad_push_event (nuv->priv->src_audio_pad,
1.853 + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0,
1.854 + GST_CLOCK_TIME_NONE, 0));
1.855 +
1.856 + if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
1.857 + nuv->priv->time_start = timestamp;
1.858 + }
1.859 + nuv->priv->new_audio_segment = FALSE;
1.860 + }
1.861 +
1.862 + break;
1.863 + }
1.864 + case 'S':
1.865 + {
1.866 + switch (h.i_compression) {
1.867 + case 'V':
1.868 + GST_DEBUG_OBJECT (nuv, "sending new video segment: %d", h.i_timecode);
1.869 + gst_pad_push_event (nuv->priv->src_video_pad,
1.870 + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, h.i_timecode * GST_MSECOND,
1.871 + GST_CLOCK_TIME_NONE, 0));
1.872 + break;
1.873 + case 'A':
1.874 + GST_DEBUG_OBJECT (nuv, "sending new audio segment: %d", h.i_timecode);
1.875 + gst_pad_push_event (nuv->priv->src_audio_pad,
1.876 + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0,
1.877 + GST_CLOCK_TIME_NONE, 0));
1.878 + break;
1.879 + default:
1.880 + break;
1.881 + }
1.882 + goto done;
1.883 + }
1.884 + default:
1.885 + break;
1.886 + }
1.887 +
1.888 + if ((buf != NULL) && (pad != NULL)) {
1.889 + /* pushing the buffer */
1.890 + gst_buffer_set_caps (buf, GST_PAD_CAPS (pad));
1.891 + ret = gst_pad_push (pad, buf);
1.892 + buf = NULL;
1.893 +
1.894 + if (ret != GST_FLOW_OK) {
1.895 + GST_WARNING_OBJECT (nuv, "error: %d pushing on srcpad %s", ret, gst_pad_get_name (pad));
1.896 +
1.897 + if (pad == nuv->priv->src_video_pad) {
1.898 + nuv->priv->last_video_return = ret;
1.899 + }
1.900 + else if (pad == nuv->priv->src_audio_pad) {
1.901 + nuv->priv->last_audio_return = ret;
1.902 + }
1.903 +
1.904 + /* verify anothers flow if is necessary stop task */
1.905 + if (gst_nuv_combine_flow (nuv) != FALSE) {
1.906 + ret = GST_FLOW_OK;
1.907 + } else {
1.908 + GST_WARNING_OBJECT (nuv, "error: on push");
1.909 + }
1.910 +
1.911 + }
1.912 + }
1.913 +
1.914 +done:
1.915 + if (buf != NULL) {
1.916 + gst_buffer_unref (buf);
1.917 + buf = NULL;
1.918 + }
1.919 + if (ret == GST_FLOW_OK) {
1.920 + nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
1.921 + memset (&nuv->priv->fh, 0, sizeof (nuv->priv->fh));
1.922 + }
1.923 + return ret;
1.924 +}
1.925 +
1.926 +static GstFlowReturn
1.927 +gst_nuv_demux_stream_mpeg_data (GstNuvDemux * nuv)
1.928 +{
1.929 + GstFlowReturn ret = GST_FLOW_OK;
1.930 +
1.931 + /* ffmpeg extra data */
1.932 + ret = gst_nuv_demux_read_bytes (nuv, nuv->priv->mpeg_data_size, TRUE,
1.933 + &nuv->priv->mpeg_buffer);
1.934 + if ((ret != GST_FLOW_OK) || (nuv->priv->mpeg_buffer == NULL)) {
1.935 + return ret;
1.936 + }
1.937 +
1.938 + GST_BUFFER_SIZE (nuv->priv->mpeg_buffer) = nuv->priv->mpeg_data_size;
1.939 + nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
1.940 + return ret;
1.941 +}
1.942 +
1.943 +static GstFlowReturn
1.944 +gst_nuv_demux_stream_extra_data (GstNuvDemux * nuv)
1.945 +{
1.946 + GstFlowReturn ret = GST_FLOW_OK;
1.947 +
1.948 + /* Load 'D' */
1.949 + nuv_frame_header h;
1.950 +
1.951 + ret = gst_nuv_demux_frame_header_load (nuv, &h);
1.952 + if (ret != GST_FLOW_OK)
1.953 + return ret;
1.954 +
1.955 + if (h.i_type != 'D') {
1.956 + GST_WARNING_OBJECT (nuv, "Unsuported rtjpeg");
1.957 + return GST_FLOW_NOT_SUPPORTED;
1.958 + }
1.959 +
1.960 + if (h.i_length > 0) {
1.961 + if (h.i_compression == 'F') {
1.962 + nuv->priv->state = GST_NUV_DEMUX_MPEG_DATA;
1.963 + } else {
1.964 + GST_WARNING_OBJECT (nuv, "only file with extended chunk are supported");
1.965 + return GST_FLOW_NOT_SUPPORTED;
1.966 + }
1.967 + } else {
1.968 + nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
1.969 + }
1.970 +
1.971 + return ret;
1.972 +}
1.973 +
1.974 +static GstFlowReturn
1.975 +gst_nuv_demux_stream_extend_header_data (GstNuvDemux * nuv)
1.976 +{
1.977 + GstFlowReturn ret = GST_FLOW_OK;
1.978 +
1.979 + ret = gst_nuv_demux_extended_header_load (nuv, &nuv->priv->eh);
1.980 + if (ret != GST_FLOW_OK)
1.981 + return ret;
1.982 +
1.983 + gst_nuv_demux_create_pads (nuv);
1.984 + nuv->priv->state = GST_NUV_DEMUX_INDEX_CREATE;
1.985 + return ret;
1.986 +}
1.987 +
1.988 +static GstFlowReturn
1.989 +gst_nuv_demux_stream_extend_header (GstNuvDemux * nuv)
1.990 +{
1.991 + GstBuffer *buf = NULL;
1.992 + GstFlowReturn res = GST_FLOW_OK;
1.993 +
1.994 + res = gst_nuv_demux_read_bytes (nuv, 1, FALSE, &buf);
1.995 + if ((res != GST_FLOW_OK) || (buf == NULL)) {
1.996 + if (buf != NULL) {
1.997 + gst_buffer_unref (buf);
1.998 + }
1.999 + return res;
1.1000 + }
1.1001 +
1.1002 + if (buf->data[0] == 'X') {
1.1003 + gst_buffer_unref (buf);
1.1004 + buf = NULL;
1.1005 + nuv_frame_header h;
1.1006 +
1.1007 + res = gst_nuv_demux_frame_header_load (nuv, &h);
1.1008 + if (res != GST_FLOW_OK)
1.1009 + return res;
1.1010 +
1.1011 + if (h.i_length != 512) {
1.1012 + return GST_FLOW_ERROR;
1.1013 + }
1.1014 + nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
1.1015 + } else {
1.1016 + nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
1.1017 + g_object_unref (buf);
1.1018 + GST_ELEMENT_WARNING (nuv, STREAM, FAILED,
1.1019 + (_("incomplete NUV support")), ("incomplete NUV support"));
1.1020 + return GST_FLOW_ERROR;
1.1021 + }
1.1022 + return res;
1.1023 +}
1.1024 +
1.1025 +static void
1.1026 +gst_nuv_demux_create_seek_index (GstNuvDemux * nuv)
1.1027 +{
1.1028 + GstMessage *msg;
1.1029 + nuv_frame_header h;
1.1030 +
1.1031 + while (gst_nuv_demux_frame_header_load (nuv, &h) == GST_FLOW_OK) {
1.1032 + if ((h.i_type == 'V') && (h.i_keyframe == 0)) {
1.1033 + frame_index_data *f = g_new0 (frame_index_data, 1);
1.1034 +
1.1035 + f->offset = nuv->priv->offset - 12;
1.1036 + f->timecode = h.i_timecode * GST_MSECOND;
1.1037 +
1.1038 + nuv->priv->index = g_slist_append (nuv->priv->index, f);
1.1039 + }
1.1040 + if (h.i_type != 'R') {
1.1041 + nuv->priv->offset += h.i_length;
1.1042 + if (h.i_type == 'A' || h.i_type == 'V')
1.1043 + nuv->priv->duration_time = h.i_timecode * GST_MSECOND;
1.1044 + }
1.1045 + }
1.1046 + GST_DEBUG_OBJECT (nuv, "CREATING INDEX: DONE : DURATION Bytes/Sec: %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1.1047 + nuv->priv->offset, nuv->priv->duration_time);
1.1048 +
1.1049 + nuv->priv->duration_bytes = nuv->priv->offset;
1.1050 + nuv->priv->offset = nuv->priv->header_lengh;
1.1051 +
1.1052 + msg = gst_message_new_duration (GST_OBJECT (nuv), GST_FORMAT_TIME, nuv->priv->duration_time);
1.1053 + gst_element_post_message (GST_ELEMENT (nuv), msg);
1.1054 +}
1.1055 +
1.1056 +static GstFlowReturn
1.1057 +gst_nuv_demux_play (GstPad * pad)
1.1058 +{
1.1059 + GstFlowReturn res = GST_FLOW_OK;
1.1060 + GstNuvDemux *nuv = GST_NUV_DEMUX (GST_PAD_PARENT (pad));
1.1061 +
1.1062 + switch (nuv->priv->state) {
1.1063 + case GST_NUV_DEMUX_START:
1.1064 + res = gst_nuv_demux_stream_file_header (nuv);
1.1065 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1066 + goto pause;
1.1067 + }
1.1068 + break;
1.1069 +
1.1070 + case GST_NUV_DEMUX_HEADER_DATA:
1.1071 + res = gst_nuv_demux_stream_header_data (nuv);
1.1072 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1073 + goto pause;
1.1074 + }
1.1075 + break;
1.1076 +
1.1077 + case GST_NUV_DEMUX_EXTRA_DATA:
1.1078 + res = gst_nuv_demux_stream_extra_data (nuv);
1.1079 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1080 + goto pause;
1.1081 + }
1.1082 + break;
1.1083 +
1.1084 + case GST_NUV_DEMUX_MPEG_DATA:
1.1085 + res = gst_nuv_demux_stream_mpeg_data (nuv);
1.1086 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1087 + goto pause;
1.1088 + }
1.1089 + break;
1.1090 +
1.1091 + case GST_NUV_DEMUX_EXTEND_HEADER:
1.1092 + res = gst_nuv_demux_stream_extend_header (nuv);
1.1093 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1094 + goto pause;
1.1095 + }
1.1096 + break;
1.1097 +
1.1098 + case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
1.1099 + res = gst_nuv_demux_stream_extend_header_data (nuv);
1.1100 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1101 + goto pause;
1.1102 + }
1.1103 + //store file header size
1.1104 + nuv->priv->header_lengh = nuv->priv->offset;
1.1105 + break;
1.1106 +
1.1107 + case GST_NUV_DEMUX_INDEX_CREATE:
1.1108 + if (nuv->priv->mode == NUV_PULL_MODE) {
1.1109 + gst_nuv_demux_create_seek_index (nuv);
1.1110 + }
1.1111 +
1.1112 + case GST_NUV_DEMUX_FRAME_HEADER:
1.1113 + res = gst_nuv_demux_read_head_frame (nuv);
1.1114 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1115 + goto pause;
1.1116 + }
1.1117 + break;
1.1118 +
1.1119 + case GST_NUV_DEMUX_MOVI:
1.1120 + res = gst_nuv_demux_stream_data (nuv);
1.1121 + if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
1.1122 + goto pause;
1.1123 + }
1.1124 + break;
1.1125 +
1.1126 + case GST_NUV_DEMUX_INVALID_DATA:
1.1127 + goto pause;
1.1128 + break;
1.1129 + default:
1.1130 + g_assert_not_reached ();
1.1131 + }
1.1132 +
1.1133 + return GST_FLOW_OK;
1.1134 +
1.1135 +pause:
1.1136 + GST_LOG_OBJECT (nuv, "pausing task, reason %s", gst_flow_get_name (res));
1.1137 + gst_pad_pause_task (nuv->priv->sinkpad);
1.1138 +
1.1139 + if (res == GST_FLOW_ERROR_EOS) {
1.1140 + gst_nuv_demux_send_eos (nuv);
1.1141 + nuv->priv->eos = TRUE;
1.1142 + res = GST_FLOW_OK;
1.1143 + }
1.1144 +
1.1145 + if (GST_FLOW_IS_FATAL (res)) {
1.1146 + GST_ELEMENT_ERROR (nuv, STREAM, FAILED,
1.1147 + (_("Internal data stream error.")),
1.1148 + ("streaming stopped, reason %s", gst_flow_get_name (res)));
1.1149 +
1.1150 + gst_nuv_demux_send_eos (nuv);
1.1151 + }
1.1152 + return res;
1.1153 +}
1.1154 +
1.1155 +static void
1.1156 +gst_nuv_demux_send_eos (GstNuvDemux * nuv)
1.1157 +{
1.1158 + gst_element_post_message (GST_ELEMENT (nuv),
1.1159 + gst_message_new_segment_done (GST_OBJECT (nuv), GST_FORMAT_TIME, -1));
1.1160 +
1.1161 + if (nuv->priv->src_video_pad)
1.1162 + gst_pad_push_event (nuv->priv->src_video_pad, gst_event_new_eos ());
1.1163 + if (nuv->priv->src_audio_pad)
1.1164 + gst_pad_push_event (nuv->priv->src_audio_pad, gst_event_new_eos ());
1.1165 +}
1.1166 +
1.1167 +static GstFlowReturn
1.1168 +gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size, gboolean move,
1.1169 + GstBuffer ** buffer)
1.1170 +{
1.1171 + GstFlowReturn ret = GST_FLOW_OK;
1.1172 +
1.1173 + if (size == 0) {
1.1174 + return ret;
1.1175 + }
1.1176 +
1.1177 +
1.1178 + if (nuv->priv->mode == NUV_PULL_MODE) {
1.1179 + ret = gst_pad_pull_range (nuv->priv->sinkpad, nuv->priv->offset, size, buffer);
1.1180 + if (ret == GST_FLOW_OK) {
1.1181 + if (move) {
1.1182 + nuv->priv->offset += size;
1.1183 + }
1.1184 + /* got eos */
1.1185 + } else if (ret == GST_FLOW_UNEXPECTED) {
1.1186 + return GST_FLOW_ERROR_EOS;
1.1187 + }
1.1188 + } else {
1.1189 + if (gst_adapter_available (nuv->priv->adapter) < size) {
1.1190 + nuv->priv->more_data = TRUE;
1.1191 + return GST_FLOW_ERROR_NO_DATA;
1.1192 + }
1.1193 + if (move) {
1.1194 + *buffer = gst_adapter_take_buffer (nuv->priv->adapter, size);
1.1195 + } else {
1.1196 + guint8 *data = NULL;
1.1197 + data = (guint8 *) gst_adapter_peek (nuv->priv->adapter, size);
1.1198 + *buffer = gst_buffer_new ();
1.1199 + gst_buffer_set_data (*buffer, data, size);
1.1200 + }
1.1201 + }
1.1202 + return ret;
1.1203 +}
1.1204 +
1.1205 +static gboolean
1.1206 +gst_nuv_demux_sink_activate (GstPad * sinkpad)
1.1207 +{
1.1208 + gboolean res = TRUE;
1.1209 + GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
1.1210 +
1.1211 + if (gst_pad_check_pull_range (sinkpad)) {
1.1212 + gst_adapter_clear (nuv->priv->adapter);
1.1213 + res = gst_pad_activate_pull (sinkpad, TRUE);
1.1214 + } else {
1.1215 + gst_adapter_clear (nuv->priv->adapter);
1.1216 + res = gst_pad_activate_push (sinkpad, TRUE);
1.1217 + }
1.1218 +
1.1219 + g_object_unref (nuv);
1.1220 + return res;
1.1221 +}
1.1222 +
1.1223 +static gboolean
1.1224 +gst_nuv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
1.1225 +{
1.1226 + GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
1.1227 +
1.1228 + if (active) {
1.1229 + GST_DEBUG_OBJECT (nuv, "activating pull function");
1.1230 + nuv->priv->mode = NUV_PULL_MODE;
1.1231 + gst_adapter_clear (nuv->priv->adapter);
1.1232 +
1.1233 + gst_pad_start_task (sinkpad, (GstTaskFunction) gst_nuv_demux_loop, sinkpad);
1.1234 + } else {
1.1235 + GST_DEBUG_OBJECT (nuv, "deactivating pull function");
1.1236 + gst_pad_stop_task (sinkpad);
1.1237 + }
1.1238 + gst_object_unref (nuv);
1.1239 +
1.1240 + return TRUE;
1.1241 +}
1.1242 +
1.1243 +static gboolean
1.1244 +gst_nuv_demux_sink_activate_push (GstPad * pad, gboolean active)
1.1245 +{
1.1246 + GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
1.1247 +
1.1248 + if (active) {
1.1249 + nuv->priv->mode = NUV_PUSH_MODE;
1.1250 + gst_adapter_clear (nuv->priv->adapter);
1.1251 +
1.1252 + GST_DEBUG_OBJECT (nuv, "activating push/chain function");
1.1253 + } else {
1.1254 + GST_DEBUG_OBJECT (nuv, "deactivating push/chain function");
1.1255 + }
1.1256 +
1.1257 + gst_object_unref (nuv);
1.1258 +
1.1259 + return TRUE;
1.1260 +}
1.1261 +
1.1262 +static frame_index_data *
1.1263 +gst_nuv_demux_do_seek_index (GstNuvDemux *nuv, gint64 seek_pos,
1.1264 + gint64 segment_stop, GstFormat format)
1.1265 +{
1.1266 + GSList *l;
1.1267 + frame_index_data *ret = NULL;
1.1268 +
1.1269 + if (nuv->priv->index == NULL) {
1.1270 + return NULL;
1.1271 + }
1.1272 +
1.1273 + /* find keyframe closest to the requested position */
1.1274 + for (l = nuv->priv->index; l != NULL; l = l->next) {
1.1275 + frame_index_data *f = (frame_index_data *) l->data;
1.1276 + gint64 pos = 0;
1.1277 +
1.1278 + if (format == GST_FORMAT_BYTES) {
1.1279 + pos = f->offset;
1.1280 + } else if (format == GST_FORMAT_TIME) {
1.1281 + pos = f->timecode;
1.1282 + } else {
1.1283 + return NULL;
1.1284 + }
1.1285 +
1.1286 + if (pos >= seek_pos) {
1.1287 + ret = f;
1.1288 + break;
1.1289 + }
1.1290 +
1.1291 + if ((segment_stop != -1) && (segment_stop != GST_CLOCK_TIME_NONE) && (pos > segment_stop)) {
1.1292 + break;
1.1293 + }
1.1294 + }
1.1295 +
1.1296 + return ret;
1.1297 +}
1.1298 +
1.1299 +static gboolean
1.1300 +gst_nuv_demux_do_seek (GstNuvDemux *nuv, GstEvent * event)
1.1301 +{
1.1302 + gdouble rate;
1.1303 + GstFormat format;
1.1304 + GstSeekFlags flags;
1.1305 + GstSeekType cur_type;
1.1306 + gint64 cur;
1.1307 + GstSeekType stop_type;
1.1308 + gint64 stop;
1.1309 + gboolean flush;
1.1310 + frame_index_data *entry;
1.1311 + gint64 segment_start;
1.1312 + gint64 segment_stop;
1.1313 + GstEvent *newsegment_event;
1.1314 +
1.1315 + if (nuv->priv->eos) {
1.1316 + return FALSE;
1.1317 + }
1.1318 +
1.1319 + if (nuv->priv->mode == NUV_PUSH_MODE) {
1.1320 + return FALSE;
1.1321 + }
1.1322 +
1.1323 +
1.1324 + gst_event_parse_seek (event, &rate, &format, &flags,
1.1325 + &cur_type, &cur, &stop_type, &stop);
1.1326 +
1.1327 +
1.1328 +
1.1329 +/*
1.1330 + if (format == GST_FORMAT_TIME) {
1.1331 + GST_DEBUG_OBJECT (nuv, "Can only seek on BYTES");
1.1332 + return FALSE;
1.1333 + }
1.1334 +*/
1.1335 +
1.1336 + if (rate <= 0.0) {
1.1337 + GST_DEBUG_OBJECT (nuv, "Can only seek with positive rate");
1.1338 + return FALSE;
1.1339 + }
1.1340 +
1.1341 + if (cur_type == GST_SEEK_TYPE_SET) {
1.1342 + GST_OBJECT_LOCK (nuv);
1.1343 + if (gst_nuv_demux_do_seek_index (nuv, cur, -1, format) == NULL) {
1.1344 + GST_DEBUG_OBJECT (nuv, "No matching seek entry in index");
1.1345 + GST_OBJECT_UNLOCK (nuv);
1.1346 + return FALSE;
1.1347 + }
1.1348 + GST_OBJECT_UNLOCK (nuv);
1.1349 + }
1.1350 +
1.1351 + flush = !!(flags & GST_SEEK_FLAG_FLUSH);
1.1352 +
1.1353 + if (flush) {
1.1354 + gst_pad_push_event (nuv->priv->sinkpad, gst_event_new_flush_start ());
1.1355 + if (nuv->priv->src_video_pad != NULL) {
1.1356 + gst_pad_push_event (nuv->priv->src_video_pad, gst_event_new_flush_start ());
1.1357 + }
1.1358 +
1.1359 + if (nuv->priv->src_audio_pad != NULL) {
1.1360 + gst_pad_push_event (nuv->priv->src_audio_pad, gst_event_new_flush_start ());
1.1361 + }
1.1362 + }
1.1363 + else {
1.1364 + gst_pad_pause_task (nuv->priv->sinkpad);
1.1365 + }
1.1366 +
1.1367 + GST_PAD_STREAM_LOCK (nuv->priv->sinkpad);
1.1368 + GST_OBJECT_LOCK (nuv);
1.1369 +
1.1370 +
1.1371 + if (cur == GST_CLOCK_TIME_NONE)
1.1372 + cur = 0;
1.1373 + if (stop == GST_CLOCK_TIME_NONE)
1.1374 + stop = nuv->priv->duration_time;
1.1375 +
1.1376 + if (cur_type == GST_SEEK_TYPE_SET)
1.1377 + segment_start = cur;
1.1378 + else if (cur_type == GST_SEEK_TYPE_CUR)
1.1379 + segment_start = nuv->priv->segment_start + cur;
1.1380 + else
1.1381 + segment_start = nuv->priv->segment_start;
1.1382 +
1.1383 + if (stop_type == GST_SEEK_TYPE_SET)
1.1384 + segment_stop = stop;
1.1385 + else if (stop_type == GST_SEEK_TYPE_CUR)
1.1386 + segment_stop = nuv->priv->segment_stop + stop;
1.1387 + else
1.1388 + segment_stop = nuv->priv->segment_stop;
1.1389 +
1.1390 + segment_start = CLAMP (segment_start, 0, nuv->priv->duration_time);
1.1391 + segment_stop = CLAMP (segment_stop, 0, nuv->priv->duration_time);
1.1392 +
1.1393 + entry = gst_nuv_demux_do_seek_index (nuv, segment_start,
1.1394 + segment_stop, format);
1.1395 +
1.1396 + if (entry == NULL) {
1.1397 + GST_DEBUG_OBJECT (nuv, "No matching seek entry in index");
1.1398 + goto seek_error;
1.1399 + }
1.1400 +
1.1401 + segment_start = entry->timecode;
1.1402 +
1.1403 + nuv->priv->segment_start = segment_start;
1.1404 + nuv->priv->segment_stop = segment_stop;
1.1405 +
1.1406 + GST_OBJECT_UNLOCK (nuv);
1.1407 +
1.1408 + if (!nuv->priv->eos) {
1.1409 + GstMessage *msg;
1.1410 + msg = gst_message_new_segment_start (GST_OBJECT (nuv), GST_FORMAT_TIME,
1.1411 + nuv->priv->segment_start);
1.1412 +
1.1413 + gst_element_post_message (GST_ELEMENT (nuv), msg);
1.1414 + }
1.1415 +
1.1416 + GST_DEBUG_OBJECT (nuv, "NEW SEGMENT START %" G_GUINT64_FORMAT ", STOP %" G_GUINT64_FORMAT,
1.1417 + segment_start, segment_stop);
1.1418 + newsegment_event = gst_event_new_new_segment (FALSE, rate,
1.1419 + GST_FORMAT_TIME, segment_start, segment_stop, segment_start);
1.1420 +
1.1421 +
1.1422 + if (flush) {
1.1423 + if (nuv->priv->src_video_pad != NULL) {
1.1424 + gst_pad_push_event (nuv->priv->src_video_pad, gst_event_new_flush_stop ());
1.1425 + }
1.1426 +
1.1427 + if (nuv->priv->src_audio_pad != NULL) {
1.1428 + gst_pad_push_event (nuv->priv->src_audio_pad, gst_event_new_flush_stop ());
1.1429 + }
1.1430 +
1.1431 + gst_pad_push_event (nuv->priv->sinkpad, gst_event_new_flush_stop ());
1.1432 + }
1.1433 +
1.1434 +
1.1435 + if (nuv->priv->src_video_pad != NULL) {
1.1436 + gst_pad_push_event (nuv->priv->src_video_pad, gst_event_ref (newsegment_event));
1.1437 + }
1.1438 + if (nuv->priv->src_audio_pad != NULL) {
1.1439 + gst_pad_push_event (nuv->priv->src_audio_pad, gst_event_ref (newsegment_event));
1.1440 + }
1.1441 +
1.1442 + gst_event_unref (newsegment_event);
1.1443 +
1.1444 + nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
1.1445 + nuv->priv->offset = entry->offset;
1.1446 +
1.1447 + gst_pad_start_task (nuv->priv->sinkpad, (GstTaskFunction) gst_nuv_demux_loop,
1.1448 + nuv->priv->sinkpad);
1.1449 +
1.1450 + GST_PAD_STREAM_UNLOCK (nuv->priv->sinkpad);
1.1451 + return TRUE;
1.1452 +
1.1453 +seek_error:
1.1454 + GST_DEBUG_OBJECT (nuv, "Got a seek error");
1.1455 + GST_OBJECT_UNLOCK (nuv);
1.1456 + GST_PAD_STREAM_UNLOCK (nuv->priv->sinkpad);
1.1457 + return FALSE;
1.1458 +
1.1459 +}
1.1460 +
1.1461 +static gboolean
1.1462 +gst_nuv_demux_srcpad_event (GstPad * pad, GstEvent * event)
1.1463 +{
1.1464 + gboolean res = FALSE;
1.1465 + GstNuvDemux *nuv;
1.1466 +
1.1467 + nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
1.1468 +
1.1469 + switch (GST_EVENT_TYPE (event)) {
1.1470 + case GST_EVENT_SEEK:
1.1471 + res = gst_nuv_demux_do_seek (nuv, event);
1.1472 + break;
1.1473 + default:
1.1474 + res = FALSE;
1.1475 + break;
1.1476 + }
1.1477 +
1.1478 + gst_object_unref (nuv);
1.1479 + return res;
1.1480 +}
1.1481 +
1.1482 +static GstFlowReturn
1.1483 +gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf)
1.1484 +{
1.1485 + GstFlowReturn ret = GST_FLOW_OK;
1.1486 + GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
1.1487 +
1.1488 + if (nuv->priv->mode != NUV_PUSH_MODE)
1.1489 + return ret;
1.1490 +
1.1491 + gst_adapter_push (nuv->priv->adapter, buf);
1.1492 +
1.1493 + while ((ret == GST_FLOW_OK) && (nuv->priv->more_data == FALSE)) {
1.1494 + ret = gst_nuv_demux_play (pad);
1.1495 + }
1.1496 +
1.1497 + nuv->priv->more_data = FALSE;
1.1498 + gst_object_unref (nuv);
1.1499 +
1.1500 + return ret;
1.1501 +}
1.1502 +
1.1503 +static void
1.1504 +gst_nuv_demux_loop (GstPad * pad)
1.1505 +{
1.1506 + gst_nuv_demux_play (pad);
1.1507 +}
1.1508 +
1.1509 +static void
1.1510 +gst_nuv_demux_index_free (gpointer data, gpointer user_data)
1.1511 +{
1.1512 + g_free (data);
1.1513 +}
1.1514 +
1.1515 +static void
1.1516 +gst_nuv_demux_reset (GstNuvDemux * nuv)
1.1517 +{
1.1518 + nuv->priv->eos = FALSE;
1.1519 + nuv->priv->more_data = FALSE;
1.1520 + nuv->priv->state = GST_NUV_DEMUX_START;
1.1521 + nuv->priv->mode = NUV_PUSH_MODE;
1.1522 + nuv->priv->offset = 0;
1.1523 + nuv->priv->time_start = 0;
1.1524 + nuv->priv->time_qos = GST_CLOCK_TIME_NONE;
1.1525 + nuv->priv->duration_bytes = GST_CLOCK_TIME_NONE;
1.1526 + nuv->priv->duration_time = GST_CLOCK_TIME_NONE;
1.1527 + nuv->priv->last_video_return = GST_FLOW_OK;
1.1528 + nuv->priv->last_audio_return = GST_FLOW_OK;
1.1529 + nuv->priv->header_lengh = 0;
1.1530 + nuv->priv->segment_stop = GST_CLOCK_TIME_NONE;
1.1531 + nuv->priv->segment_start = GST_CLOCK_TIME_NONE;
1.1532 +
1.1533 + //clear index list
1.1534 + g_slist_foreach (nuv->priv->index, gst_nuv_demux_index_free, NULL);
1.1535 + g_slist_free (nuv->priv->index);
1.1536 + nuv->priv->index = NULL;
1.1537 +
1.1538 + gst_adapter_clear (nuv->priv->adapter);
1.1539 +
1.1540 + if (nuv->priv->mpeg_buffer != NULL) {
1.1541 + gst_buffer_unref (nuv->priv->mpeg_buffer);
1.1542 + nuv->priv->mpeg_buffer = NULL;
1.1543 + }
1.1544 +}
1.1545 +
1.1546 +static void
1.1547 +gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv)
1.1548 +{
1.1549 + if (nuv->priv->src_video_pad) {
1.1550 + gst_element_remove_pad (GST_ELEMENT (nuv), nuv->priv->src_video_pad);
1.1551 + nuv->priv->src_video_pad = NULL;
1.1552 + }
1.1553 +
1.1554 + if (nuv->priv->src_audio_pad) {
1.1555 + gst_element_remove_pad (GST_ELEMENT (nuv), nuv->priv->src_audio_pad);
1.1556 + nuv->priv->src_audio_pad = NULL;
1.1557 + }
1.1558 +}
1.1559 +
1.1560 +static GstStateChangeReturn
1.1561 +gst_nuv_demux_change_state (GstElement * element, GstStateChange transition)
1.1562 +{
1.1563 + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1.1564 +
1.1565 + switch (transition) {
1.1566 + case GST_STATE_CHANGE_NULL_TO_READY:
1.1567 + gst_nuv_demux_reset (GST_NUV_DEMUX (element));
1.1568 + gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (element));
1.1569 + break;
1.1570 + default:
1.1571 + break;
1.1572 + }
1.1573 +
1.1574 + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1.1575 + if (ret == GST_STATE_CHANGE_FAILURE) {
1.1576 + goto done;
1.1577 + }
1.1578 +
1.1579 + switch (transition) {
1.1580 + case GST_STATE_CHANGE_READY_TO_NULL:
1.1581 + gst_nuv_demux_reset (GST_NUV_DEMUX (element));
1.1582 + gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (element));
1.1583 + break;
1.1584 + default:
1.1585 + break;
1.1586 + }
1.1587 +
1.1588 +done:
1.1589 + return ret;
1.1590 +}
1.1591 +
1.1592 +#if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
1.1593 +GstBuffer *
1.1594 +gst_adapter_take_buffer (GstAdapter * adapter, guint nbytes)
1.1595 +{
1.1596 + GstBuffer *buffer;
1.1597 + GstBuffer *cur;
1.1598 + guint8 *data;
1.1599 +
1.1600 + g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
1.1601 + g_return_val_if_fail (nbytes > 0, NULL);
1.1602 +
1.1603 + GST_LOG_OBJECT (adapter, "taking buffer of %u bytes", nbytes);
1.1604 +
1.1605 + /* we don't have enough data, return NULL. This is unlikely
1.1606 + * as one usually does an _available() first instead of peeking a
1.1607 + * random size. */
1.1608 + if (G_UNLIKELY (nbytes > adapter->size))
1.1609 + return NULL;
1.1610 +
1.1611 + /* our head buffer has enough data left, return it */
1.1612 + cur = adapter->buflist->data;
1.1613 + if (GST_BUFFER_SIZE (cur) >= nbytes + adapter->skip) {
1.1614 + GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
1.1615 + nbytes);
1.1616 + buffer = gst_buffer_create_sub (cur, adapter->skip, nbytes);
1.1617 +
1.1618 + gst_adapter_flush (adapter, nbytes);
1.1619 +
1.1620 + return buffer;
1.1621 + }
1.1622 +
1.1623 + data = gst_adapter_take (adapter, nbytes);
1.1624 + if (data == NULL)
1.1625 + return NULL;
1.1626 +
1.1627 + buffer = gst_buffer_new ();
1.1628 + GST_BUFFER_DATA (buffer) = data;
1.1629 + GST_BUFFER_MALLOCDATA (buffer) = data;
1.1630 + GST_BUFFER_SIZE (buffer) = nbytes;
1.1631 +
1.1632 + return buffer;
1.1633 +}
1.1634 +#endif
1.1635 +
1.1636 +static void
1.1637 +gst_nuv_typefind (GstTypeFind * tf, gpointer unused)
1.1638 +{
1.1639 + guint8 *data = gst_type_find_peek (tf, 0, 11);
1.1640 +
1.1641 + if (data) {
1.1642 + if (memcmp (data, "MythTVVideo", 11) == 0
1.1643 + || memcmp (data, "NuppelVideo", 11) == 0) {
1.1644 + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM,
1.1645 + gst_caps_new_simple ("video/x-nuv", NULL));
1.1646 + }
1.1647 + }
1.1648 +}
1.1649 +
1.1650 +static gboolean
1.1651 +plugin_init (GstPlugin * plugin)
1.1652 +{
1.1653 + static gchar *exts[] = { "nuv", NULL };
1.1654 +#ifdef ENABLE_NLS
1.1655 + setlocale (LC_ALL, "");
1.1656 + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1.1657 +#endif /* ENABLE_NLS */
1.1658 +
1.1659 + if (!gst_element_register (plugin, "nuvdemux", GST_RANK_SECONDARY,
1.1660 + GST_TYPE_NUV_DEMUX)) {
1.1661 + return FALSE;
1.1662 + }
1.1663 +
1.1664 + if (!gst_type_find_register (plugin, "video/x-nuv", GST_RANK_SECONDARY,
1.1665 + gst_nuv_typefind,
1.1666 + exts,
1.1667 + gst_caps_new_simple ("video/x-nuv", NULL), NULL, NULL)) {
1.1668 + GST_WARNING ("can't register typefind");
1.1669 + return FALSE;
1.1670 + }
1.1671 +
1.1672 + return TRUE;
1.1673 +}
1.1674 +
1.1675 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1.1676 + GST_VERSION_MINOR,
1.1677 + "nuvdemux",
1.1678 + "Demuxes and muxes audio and video",
1.1679 + plugin_init, VERSION, "LGPL", "NuvDemux", "")
1.1680 +