gst-gmyth/nuvdemux/gstnuvdemux.c
author renatofilho
Thu Jun 14 18:21:53 2007 +0100 (2007-06-14)
branchtrunk
changeset 752 b7f71ba285da
parent 725 a102805611e7
child 754 cb885ee44618
permissions -rw-r--r--
[svn r758] fixed indent using GNU Style
     1 /* GStreamer
     2  * Copyright (C) <2006> Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
     3  *                      Rosfran Borges <rosfran.borges@indt.org.br>
     4  *
     5  * This library is free software; you can redistribute it and/or
     6  * modify it under the terms of the GNU Library General Public
     7  * License as published by the Free Software Foundation; either
     8  * version 2 of the License, or (at your option) any later version.
     9  *
    10  * This library is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  * Library General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU Library General Public
    16  * License along with this library; if not, write to the
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    18  * Boston, MA 02111-1307, USA.
    19  */
    20 /* Element-Checklist-Version: 5 */
    21 
    22 /**
    23  * SECTION:element-nuvdemux
    24  *
    25  * <refsect2>
    26  * <para>
    27  * Demuxes an .nuv file into raw or compressed audio and/or video streams.
    28  * </para>
    29  * <para>
    30  * This element currently only supports pull-based scheduling.
    31  * </para>
    32  * <title>Example launch line</title>
    33  * <para>
    34  * <programlisting>
    35  * gst-launch filesrc test.nuv ! nuvdemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
    36  * </programlisting>
    37  * Play (parse and decode) an .nuv file and try to output it to
    38  * an automatically detected soundcard and videosink. If the NUV file contains
    39  * compressed audio or video data, this will only work if you have the
    40  * right decoder elements/plugins installed.
    41  * </para>
    42  * </refsect2>
    43  *
    44  */
    45 
    46 #ifdef HAVE_CONFIG_H
    47 #include "config.h"
    48 #endif
    49 
    50 #include <gst/gst.h>
    51 #include <gst/gsterror.h>
    52 #include <gst/gstplugin.h>
    53 #include <string.h>
    54 #include <math.h>
    55 
    56 #include "glib/gi18n.h"
    57 #include "gstnuvdemux.h"
    58 
    59 #define GST_NUV_DEMUX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_NUV_DEMUX, GstNuvDemuxPrivate))
    60 
    61 GST_DEBUG_CATEGORY_STATIC(nuvdemux_debug);
    62 #define GST_CAT_DEFAULT nuvdemux_debug
    63 #define GST_FLOW_ERROR_NO_DATA  -101
    64 #define GST_FLOW_ERROR_EOS	-102
    65 
    66 enum
    67 {
    68   NUV_PUSH_MODE = 0,
    69   NUV_PULL_MODE
    70 };
    71 
    72 GST_DEBUG_CATEGORY_EXTERN(GST_CAT_EVENT);
    73 
    74 static const GstElementDetails gst_nuv_demux_details =
    75 GST_ELEMENT_DETAILS("Nuv demuxer",
    76 					"Codec/Demuxer",
    77 					"Demultiplex a .nuv file into audio and video",
    78 					"Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
    79 					"Rosfran Borges <rosfran.borges@indt.org.br>");
    80 
    81 
    82 /* file header */
    83 typedef struct
    84 {
    85   gchar id[12];					/* "NuppelVideo\0" or "MythTVVideo\0" */
    86   gchar version[5];				/* "x.xx\0" */
    87 
    88   gint i_width;
    89   gint i_height;
    90   gint i_width_desired;
    91   gint i_height_desired;
    92 
    93   gchar i_mode;					/* P progressive, I interlaced */
    94 
    95   gdouble d_aspect;				/* 1.0 squared pixel */
    96   gdouble d_fps;
    97  //fps num/denom
    98   gint i_fpsn;
    99   gint i_fpsd;
   100 
   101   gint i_video_blocks;			/* 0 no video, -1 unknown */
   102   gint i_audio_blocks;
   103   gint i_text_blocks;
   104 
   105   gint i_keyframe_distance;
   106 
   107 } nuv_header;
   108 
   109 /* frame header */
   110 typedef struct
   111 {
   112   gchar i_type;					/* A: audio, V: video, S: sync; T: test
   113 								   R: Seekpoint (string:RTjjjjjjjj)
   114 								   D: Extra data for codec */
   115   gchar i_compression;			/* V: 0 uncompressed
   116 								   1 RTJpeg
   117 								   2 RTJpeg+lzo
   118 								   N black frame
   119 								   L copy last
   120 								   A: 0 uncompressed (44100 1-bits, 2ch)
   121 								   1 lzo
   122 								   2 layer 2
   123 								   3 layer 3
   124 								   F flac
   125 								   S shorten
   126 								   N null frame loudless
   127 								   L copy last
   128 								   S: B audio and vdeo sync point
   129 								   A audio sync info (timecode == effective
   130 								   dsp frequency*100)
   131 								   V next video sync (timecode == next video
   132 								   frame num)
   133 								   S audio,video,text correlation */
   134   gchar i_keyframe;				/* 0 keyframe, else no no key frame */
   135   guint8 i_filters;				/* 0x01: gauss 5 pixel (8,2,2,2,2)/16
   136 								   0x02: gauss 5 pixel (8,1,1,1,1)/12
   137 								   0x04: cartoon filter */
   138 
   139   gint32 i_timecode;			/* ms */
   140 
   141   gint i_length;				/* V,A,T: length of following data
   142 								   S: length of packet correl */
   143 } nuv_frame_header;
   144 
   145 
   146 /* FIXME Not sure of this one */
   147 typedef struct
   148 {
   149   gint i_version;
   150   guint32 i_video_fcc;
   151 
   152   guint32 i_audio_fcc;
   153   gint i_audio_sample_rate;
   154   gint i_audio_bits_per_sample;
   155   gint i_audio_channels;
   156   gint i_audio_compression_ratio;
   157   gint i_audio_quality;
   158   gint i_rtjpeg_quality;
   159   gint i_rtjpeg_luma_filter;
   160   gint i_rtjpeg_chroma_filter;
   161   gint i_lavc_bitrate;
   162   gint i_lavc_qmin;
   163   gint i_lavc_qmax;
   164   gint i_lavc_maxqdiff;
   165   gint64 i_seekable_offset;
   166   gint64 i_keyframe_adjust_offset;
   167 
   168 } nuv_extended_header;
   169 
   170 typedef struct
   171 {
   172   gint64 timecode;
   173   gint64 offset;
   174 
   175 } frame_index_data;
   176 
   177 typedef enum
   178 {
   179   GST_NUV_DEMUX_START,
   180   GST_NUV_DEMUX_HEADER_DATA,
   181   GST_NUV_DEMUX_EXTRA_DATA,
   182   GST_NUV_DEMUX_MPEG_DATA,
   183   GST_NUV_DEMUX_EXTEND_HEADER,
   184   GST_NUV_DEMUX_EXTEND_HEADER_DATA,
   185   GST_NUV_DEMUX_INDEX_CREATE,
   186   GST_NUV_DEMUX_FRAME_HEADER,
   187   GST_NUV_DEMUX_MOVI,
   188   GST_NUV_DEMUX_INVALID_DATA
   189 } GstNuvDemuxState;
   190 
   191 struct _GstNuvDemuxPrivate
   192 {
   193  /* used for indicate the mode */
   194   guint mode;
   195 
   196  /* used on push mode */
   197   GstAdapter *adapter;
   198 
   199  /* pads */
   200   GstPad *sinkpad;
   201   GstPad *src_video_pad;
   202   GstPad *src_audio_pad;
   203 
   204  /* Flow control */
   205   GstFlowReturn last_video_return;
   206   GstFlowReturn last_audio_return;
   207   gboolean more_data;
   208   gboolean eos;
   209   gboolean new_file;
   210   guint segment;
   211 
   212  /* NUV decoding state */
   213   GstNuvDemuxState state;
   214   guint64 offset;
   215 
   216  /* duration information */
   217   guint64 duration_bytes;
   218   guint64 duration_time;
   219   guint64 segment_stop;
   220   guint64 segment_start;
   221 
   222  /* segment control info */
   223   gboolean new_audio_segment;
   224   gboolean new_video_segment;
   225 
   226  /* Mpeg ExtraData */
   227   guint64 mpeg_data_size;
   228   GstBuffer *mpeg_buffer;
   229 
   230  /* Headers */
   231   nuv_header h;
   232   nuv_extended_header eh;
   233   nuv_frame_header fh;
   234 
   235  /* anothers info */
   236   guint64 header_lengh;
   237   gint64 time_start;
   238   gint64 time_diff;
   239   gint64 time_qos;
   240   guint64 last_frame_time;
   241   GSList *index;
   242 };
   243 
   244 
   245 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE("sink",
   246 																	GST_PAD_SINK,
   247 																	GST_PAD_ALWAYS,
   248 																	GST_STATIC_CAPS
   249 																	("video/x-nuv"));
   250 
   251 static GstStaticPadTemplate audio_src_template =
   252 GST_STATIC_PAD_TEMPLATE("audio_src",
   253 						GST_PAD_SRC,
   254 						GST_PAD_SOMETIMES,
   255 						GST_STATIC_CAPS_ANY);
   256 
   257 static GstStaticPadTemplate video_src_template =
   258 GST_STATIC_PAD_TEMPLATE("video_src",
   259 						GST_PAD_SRC,
   260 						GST_PAD_SOMETIMES,
   261 						GST_STATIC_CAPS_ANY);
   262 
   263 static void gst_nuv_demux_dispose(GObject * object);
   264 static void gst_nuv_demux_finalize(GObject * object);
   265 static GstStateChangeReturn gst_nuv_demux_change_state(GstElement * element,
   266 													   GstStateChange
   267 													   transition);
   268 static void gst_nuv_demux_loop(GstPad * pad);
   269 static GstFlowReturn gst_nuv_demux_chain(GstPad * pad, GstBuffer * buf);
   270 static GstFlowReturn gst_nuv_demux_play(GstPad * pad);
   271 static gboolean gst_nuv_demux_sink_activate_pull(GstPad * sinkpad,
   272 												 gboolean active);
   273 static gboolean gst_nuv_demux_sink_activate_push(GstPad * pad,
   274 												 gboolean active);
   275 static gboolean gst_nuv_demux_sink_activate(GstPad * sinkpad);
   276 static gboolean gst_nuv_demux_sink_event(GstPad * pad, GstEvent * event);
   277 static gboolean gst_nuv_demux_srcpad_event(GstPad * pad, GstEvent * event);
   278 static frame_index_data *gst_nuv_demux_do_seek_index(GstNuvDemux * nuv,
   279 													 gint64 seek_pos,
   280 													 gint64 segment_stop,
   281 													 GstFormat format);
   282 
   283 
   284 static GstFlowReturn gst_nuv_demux_move_bytes(GstNuvDemux * nuv,
   285 											  guint64 size);
   286 static GstFlowReturn gst_nuv_demux_read_bytes(GstNuvDemux * nuv, guint64 size,
   287 											  gboolean move,
   288 											  GstBuffer ** buffer);
   289 static void gst_nuv_demux_reset(GstNuvDemux * nuv);
   290 static void gst_nuv_demux_destoy_src_pad(GstNuvDemux * nuv);
   291 static void gst_nuv_demux_send_eos(GstNuvDemux * nuv);
   292 static void gst_nuv_demux_create_seek_index(GstNuvDemux * nuv);
   293 
   294 
   295 #if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
   296 GstBuffer *gst_adapter_take_buffer(GstAdapter * adapter, guint nbytes);
   297 #endif
   298 
   299 
   300 GST_BOILERPLATE(GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
   301 
   302 /******************************************************************************
   303  * Utils function
   304  ******************************************************************************/
   305 #if G_BYTE_ORDER == G_BIG_ENDIAN
   306 static inline gdouble
   307 _gdouble_swap_le_be(gdouble * d)
   308 {
   309   union
   310   {
   311 	guint64 i;
   312 	gdouble d;
   313   } u;
   314 
   315   u.d = *d;
   316   u.i = GUINT64_SWAP_LE_BE(u.i);
   317   return u.d;
   318 }
   319 
   320 #define READ_DOUBLE_FROM_LE(d) (_gdouble_swap_le_be((gdouble* ) d))
   321 #else /* G_BYTE_ORDER != G_BIG_ENDIAN */
   322 #define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
   323 #endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
   324 
   325 static void
   326 double2fraction(double in, int *num, int *denom)
   327 {
   328   if (in == 29.97)
   329 	{
   330 	  *num = 30000;
   331 	  *denom = 1001;
   332 	}
   333   else if (in == 23.976)
   334 	{
   335 	  *num = 24000;
   336 	  *denom = 1001;
   337 	}
   338   else
   339 	{
   340 	  *denom = 1;
   341 	  while (in - floor(in) >= 0.1)
   342 		{
   343 		  *denom *= 10;
   344 		  in *= 10.0;
   345 		}
   346 	  *num = (int) floor(in);
   347 	}
   348 }
   349 
   350 /* GObject Functions */
   351 
   352 static void
   353 gst_nuv_demux_base_init(gpointer klass)
   354 {
   355   GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
   356 
   357   gst_element_class_add_pad_template(element_class,
   358 									 gst_static_pad_template_get
   359 									 (&audio_src_template));
   360 
   361   gst_element_class_add_pad_template(element_class,
   362 									 gst_static_pad_template_get
   363 									 (&video_src_template));
   364 
   365   gst_element_class_add_pad_template(element_class,
   366 									 gst_static_pad_template_get
   367 									 (&sink_template));
   368   gst_element_class_set_details(element_class, &gst_nuv_demux_details);
   369 }
   370 
   371 static void
   372 gst_nuv_demux_class_init(GstNuvDemuxClass * klass)
   373 {
   374   GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass);
   375   GObjectClass *gobject_class = (GObjectClass *) klass;
   376 
   377   GST_DEBUG_CATEGORY_INIT(nuvdemux_debug, "nuvdemux",
   378 						  0, "Demuxer for NUV streams");
   379 
   380   parent_class = g_type_class_peek_parent(klass);
   381 
   382   gobject_class->dispose = gst_nuv_demux_dispose;
   383   gobject_class->finalize = gst_nuv_demux_finalize;
   384   gstelement_class->change_state = gst_nuv_demux_change_state;
   385 
   386   g_type_class_add_private(gobject_class, sizeof(GstNuvDemuxPrivate));
   387 }
   388 
   389 static void
   390 gst_nuv_demux_init(GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
   391 {
   392   nuv->priv = GST_NUV_DEMUX_GET_PRIVATE(nuv);
   393   nuv->priv->sinkpad =
   394 	gst_pad_new_from_static_template(&sink_template, "sink");
   395 
   396  /* creating adapter */
   397   nuv->priv->mode = NUV_PUSH_MODE;
   398   nuv->priv->adapter = gst_adapter_new();
   399 
   400   nuv->priv->new_audio_segment = TRUE;
   401   nuv->priv->new_video_segment = TRUE;
   402 
   403   gst_pad_set_activate_function(nuv->priv->sinkpad,
   404 								gst_nuv_demux_sink_activate);
   405   gst_pad_set_activatepull_function(nuv->priv->sinkpad,
   406 									gst_nuv_demux_sink_activate_pull);
   407   gst_pad_set_activatepush_function(nuv->priv->sinkpad,
   408 									gst_nuv_demux_sink_activate_push);
   409   gst_pad_set_chain_function(nuv->priv->sinkpad,
   410 							 GST_DEBUG_FUNCPTR(gst_nuv_demux_chain));
   411   gst_pad_set_event_function(nuv->priv->sinkpad,
   412 							 GST_DEBUG_FUNCPTR(gst_nuv_demux_sink_event));
   413 
   414 
   415   gst_element_add_pad(GST_ELEMENT(nuv), nuv->priv->sinkpad);
   416 
   417 }
   418 
   419 static void
   420 gst_nuv_demux_dispose(GObject * object)
   421 {
   422   GstNuvDemux *nuv = GST_NUV_DEMUX(object);
   423 
   424 
   425   if (nuv->priv->mpeg_buffer != NULL)
   426 	{
   427 	  gst_buffer_unref(nuv->priv->mpeg_buffer);
   428 	}
   429 
   430   gst_nuv_demux_reset(GST_NUV_DEMUX(object));
   431   gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(object));
   432 
   433   if (nuv->priv->adapter != NULL)
   434 	{
   435 	  gst_object_unref(nuv->priv->adapter);
   436 	}
   437 }
   438 
   439 static void
   440 gst_nuv_demux_finalize(GObject * object)
   441 {
   442   G_OBJECT_CLASS(parent_class)->finalize(object);
   443 }
   444 
   445 
   446 /* HeaderLoad:
   447  */
   448 static GstFlowReturn
   449 gst_nuv_demux_header_load(GstNuvDemux * nuv, nuv_header * h)
   450 {
   451   GstBuffer *buffer = NULL;
   452   GstFlowReturn res = gst_nuv_demux_read_bytes(nuv, 72, TRUE, &buffer);
   453 
   454   if ((res != GST_FLOW_OK) || (buffer == NULL))
   455 	{
   456 	  goto done;
   457 	}
   458 
   459   if (h != NULL)
   460 	{
   461 	  memcpy(h->id, buffer->data, 12);
   462 	  memcpy(h->version, buffer->data + 12, 5);
   463 	  h->i_width = GST_READ_UINT32_LE(&buffer->data[20]);
   464 	  h->i_height = GST_READ_UINT32_LE(&buffer->data[24]);
   465 	  h->i_width_desired = GST_READ_UINT32_LE(&buffer->data[28]);
   466 	  h->i_height_desired = GST_READ_UINT32_LE(&buffer->data[32]);
   467 	  h->i_mode = GPOINTER_TO_INT(buffer->data[36]);
   468 	  h->d_aspect = READ_DOUBLE_FROM_LE(&buffer->data[40]);
   469 	  h->d_fps = READ_DOUBLE_FROM_LE(&buffer->data[48]);
   470 	 /* get the num and denom values from fps */
   471 	  double2fraction(h->d_fps, &h->i_fpsn, &h->i_fpsd);
   472 	  h->i_video_blocks = GST_READ_UINT32_LE(&buffer->data[56]);
   473 	  h->i_audio_blocks = GST_READ_UINT32_LE(&buffer->data[60]);
   474 	  h->i_text_blocks = GST_READ_UINT32_LE(&buffer->data[64]);
   475 	  h->i_keyframe_distance = GST_READ_UINT32_LE(&buffer->data[68]);
   476 
   477 	  GST_DEBUG_OBJECT(nuv,
   478 					   "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d",
   479 					   h->id, h->version, h->i_width, h->i_height,
   480 					   h->d_aspect, h->d_fps, h->i_video_blocks,
   481 					   h->i_audio_blocks, h->i_text_blocks,
   482 					   h->i_keyframe_distance);
   483 	}
   484 
   485 done:
   486   if (buffer != NULL)
   487 	{
   488 	  gst_buffer_unref(buffer);
   489 	  buffer = NULL;
   490 	}
   491   return res;
   492 }
   493 
   494 static GstFlowReturn
   495 gst_nuv_demux_stream_header_data(GstNuvDemux * nuv)
   496 {
   497   GstFlowReturn res;
   498 
   499   if (nuv->priv->new_file)
   500 	res = gst_nuv_demux_header_load(nuv, NULL);
   501   else
   502 	res = gst_nuv_demux_header_load(nuv, &nuv->priv->h);
   503 
   504   if (res == GST_FLOW_OK)
   505 	nuv->priv->state = GST_NUV_DEMUX_EXTRA_DATA;
   506   return res;
   507 }
   508 
   509 /*
   510  * Read NUV file tag
   511  */
   512 static GstFlowReturn
   513 gst_nuv_demux_stream_file_header(GstNuvDemux * nuv)
   514 {
   515   GstFlowReturn res = GST_FLOW_OK;
   516   GstBuffer *file_header = NULL;
   517 
   518   res = gst_nuv_demux_read_bytes(nuv, 12, FALSE, &file_header);
   519   if (res == GST_FLOW_OK)
   520 	{
   521 	  if (strncmp((gchar *) file_header->data, "MythTVVideo", 11) ||
   522 		  strncmp((gchar *) file_header->data, "NuppelVideo", 11))
   523 		{
   524 		  nuv->priv->state = GST_NUV_DEMUX_HEADER_DATA;
   525 		}
   526 	  else
   527 		{
   528 		  GST_DEBUG_OBJECT(nuv, "error parsing file header");
   529 		  nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
   530 		  res = GST_FLOW_ERROR;
   531 		}
   532 	}
   533 
   534   if (file_header != NULL)
   535 	{
   536 	  gst_buffer_unref(file_header);
   537 	  file_header = NULL;
   538 	}
   539   return res;
   540 }
   541 
   542 /* FrameHeaderLoad:
   543  */
   544 static GstFlowReturn
   545 gst_nuv_demux_frame_header_load(GstNuvDemux * nuv, nuv_frame_header * h)
   546 {
   547   unsigned char *data;
   548   GstBuffer *buf = NULL;
   549 
   550   GstFlowReturn res = gst_nuv_demux_read_bytes(nuv, 12, TRUE, &buf);
   551 
   552   if ((res != GST_FLOW_OK) || (buf == NULL))
   553 	{
   554 	  goto done;
   555 	}
   556 
   557   if (h == NULL)
   558 	goto done;
   559 
   560   data = buf->data;
   561 
   562   h->i_type = GPOINTER_TO_INT(data[0]);
   563   h->i_compression = GPOINTER_TO_INT(data[1]);
   564   h->i_keyframe = GPOINTER_TO_INT(data[2]);
   565   h->i_filters = GPOINTER_TO_INT(data[3]);
   566   h->i_timecode = GST_READ_UINT32_LE(&data[4]);
   567   h->i_length = GST_READ_UINT32_LE(&data[8]);
   568 
   569   GST_DEBUG_OBJECT(nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
   570 				   h->i_type,
   571 				   h->i_compression ? h->i_compression : ' ',
   572 				   h->i_keyframe ? h->i_keyframe : ' ',
   573 				   h->i_filters, h->i_timecode, h->i_length);
   574 
   575 done:
   576   if (buf != NULL)
   577 	{
   578 	  gst_buffer_unref(buf);
   579 	  buf = NULL;
   580 	}
   581 
   582   return res;
   583 }
   584 
   585 static GstFlowReturn
   586 gst_nuv_demux_extended_header_load(GstNuvDemux * nuv, nuv_extended_header * h)
   587 {
   588   unsigned char *data;
   589   GstBuffer *buff = NULL;
   590 
   591   GstFlowReturn res = gst_nuv_demux_read_bytes(nuv, 512, TRUE, &buff);
   592 
   593   if ((res != GST_FLOW_OK) || (buff == NULL))
   594 	{
   595 	  goto done;
   596 	}
   597 
   598   if (h == NULL)
   599 	goto done;
   600 
   601   data = buff->data;
   602   h->i_version = GST_READ_UINT32_LE(&data[0]);
   603   h->i_video_fcc = GST_MAKE_FOURCC(data[4], data[5], data[6], data[7]);
   604   h->i_audio_fcc = GST_MAKE_FOURCC(data[8], data[9], data[10], data[11]);
   605   h->i_audio_sample_rate = GST_READ_UINT32_LE(&data[12]);
   606   h->i_audio_bits_per_sample = GST_READ_UINT32_LE(&data[16]);
   607   h->i_audio_channels = GST_READ_UINT32_LE(&data[20]);
   608   h->i_audio_compression_ratio = GST_READ_UINT32_LE(&data[24]);
   609   h->i_audio_quality = GST_READ_UINT32_LE(&data[28]);
   610   h->i_rtjpeg_quality = GST_READ_UINT32_LE(&data[32]);
   611   h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE(&data[36]);
   612   h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE(&data[40]);
   613   h->i_lavc_bitrate = GST_READ_UINT32_LE(&data[44]);
   614   h->i_lavc_qmin = GST_READ_UINT32_LE(&data[48]);
   615   h->i_lavc_qmin = GST_READ_UINT32_LE(&data[52]);
   616   h->i_lavc_maxqdiff = GST_READ_UINT32_LE(&data[56]);
   617   h->i_seekable_offset = GST_READ_UINT64_LE(&data[60]);
   618   h->i_keyframe_adjust_offset = GST_READ_UINT64_LE(&data[68]);
   619 
   620   GST_DEBUG_OBJECT(nuv,
   621 				   "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d"
   622 				   "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld",
   623 				   h->i_version, (gchar *) & h->i_video_fcc,
   624 				   (gchar *) & h->i_audio_fcc, h->i_audio_sample_rate,
   625 				   h->i_audio_bits_per_sample, h->i_audio_channels,
   626 				   h->i_audio_compression_ratio, h->i_audio_quality,
   627 				   h->i_rtjpeg_quality, h->i_rtjpeg_luma_filter,
   628 				   h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate,
   629 				   h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff,
   630 				   h->i_seekable_offset, h->i_keyframe_adjust_offset);
   631 
   632 done:
   633   if (buff != NULL)
   634 	{
   635 	  gst_buffer_unref(buff);
   636 	  buff = NULL;
   637 	}
   638   return res;
   639 }
   640 
   641 
   642 /* Query Functions */
   643 static const GstQueryType *
   644 gst_nuv_demux_get_src_query_types(GstPad * pad)
   645 {
   646   static const GstQueryType src_types[] = {
   647 	GST_QUERY_POSITION,
   648 	GST_QUERY_DURATION,
   649 	0
   650   };
   651 
   652   return src_types;
   653 }
   654 
   655 static gboolean
   656 gst_nuv_demux_handle_src_query(GstPad * pad, GstQuery * query)
   657 {
   658   gboolean res = FALSE;
   659   GstNuvDemux *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
   660 
   661 
   662   switch (GST_QUERY_TYPE(query))
   663 	{
   664 	case GST_QUERY_POSITION:
   665 	  {
   666 		GstFormat format;
   667 		gst_query_parse_position(query, &format, NULL);
   668 		switch (format)
   669 		  {
   670 		  case GST_FORMAT_TIME:
   671 			if (GST_CLOCK_TIME_IS_VALID(nuv->priv->last_frame_time))
   672 			  {
   673 				gst_query_set_position(query, GST_FORMAT_TIME,
   674 									   nuv->priv->last_frame_time);
   675 				res = TRUE;
   676 			  }
   677 			break;
   678 		  default:
   679 			break;
   680 		  }
   681 		break;
   682 	  }
   683 	case GST_QUERY_DURATION:
   684 	  {
   685 		GstFormat format;
   686 		gst_query_parse_duration(query, &format, NULL);
   687 		switch (format)
   688 		  {
   689 		  case GST_FORMAT_TIME:
   690 			if (nuv->priv->duration_time != GST_CLOCK_TIME_NONE)
   691 			  {
   692 				gst_query_set_duration(query, GST_FORMAT_TIME,
   693 									   nuv->priv->duration_time);
   694 				res = TRUE;
   695 			  }
   696 			break;
   697 		  default:
   698 			break;
   699 		  }
   700 		break;
   701 	  }
   702 	default:
   703 	  break;
   704 	}
   705 
   706   if (res == FALSE)
   707 	{
   708 	  res = gst_pad_query_default(pad, query);
   709 	}
   710 
   711   gst_object_unref(nuv);
   712   return res;
   713 }
   714 
   715 static GstPad *
   716 gst_nuv_demux_create_pad(GstNuvDemux * nuv, GstCaps * caps,
   717 						 GstStaticPadTemplate * template, const gchar * name)
   718 {
   719   GstPad *pad = NULL;
   720   pad = gst_pad_new_from_static_template(template, name);
   721   gst_pad_set_caps(pad, caps);
   722   gst_pad_set_active(pad, TRUE);
   723   gst_pad_use_fixed_caps(pad);
   724   gst_element_add_pad(GST_ELEMENT(nuv), pad);
   725 
   726   gst_pad_set_event_function(pad,
   727 							 GST_DEBUG_FUNCPTR(gst_nuv_demux_srcpad_event));
   728 
   729   gst_pad_set_query_type_function(pad,
   730 								  GST_DEBUG_FUNCPTR
   731 								  (gst_nuv_demux_get_src_query_types));
   732 
   733   gst_pad_set_query_function(pad,
   734 							 GST_DEBUG_FUNCPTR
   735 							 (gst_nuv_demux_handle_src_query));
   736 
   737 
   738   return pad;
   739 }
   740 
   741 static void
   742 gst_nuv_demux_create_pads(GstNuvDemux * nuv)
   743 {
   744   if (nuv->priv->h.i_video_blocks != 0)
   745 	{
   746 	  GstCaps *video_caps = NULL;
   747 
   748 	  video_caps = gst_caps_new_simple("video/x-divx",
   749 									   "divxversion", G_TYPE_INT, 4,
   750 									   "width", G_TYPE_INT,
   751 									   nuv->priv->h.i_width, "height",
   752 									   G_TYPE_INT, nuv->priv->h.i_height,
   753 									   "framerate", GST_TYPE_FRACTION,
   754 									   nuv->priv->h.i_fpsn,
   755 									   nuv->priv->h.i_fpsd, "format",
   756 									   GST_TYPE_FOURCC,
   757 									   nuv->priv->eh.i_video_fcc,
   758 									   "pixel-aspect-ratio",
   759 									   GST_TYPE_FRACTION,
   760 									   (gint) (nuv->priv->h.d_aspect *
   761 											   1000.0f), 1000, NULL);
   762 
   763 	  nuv->priv->src_video_pad =
   764 		gst_nuv_demux_create_pad(nuv, video_caps, &video_src_template,
   765 								 "video_src");
   766 	  gst_caps_unref(video_caps);
   767 	}
   768 
   769   if (nuv->priv->h.i_audio_blocks != 0)
   770 	{
   771 	  GstCaps *audio_caps = NULL;
   772 
   773 	  audio_caps = gst_caps_new_simple("audio/mpeg", "rate", G_TYPE_INT, nuv->priv->eh.i_audio_sample_rate, "format", GST_TYPE_FOURCC, nuv->priv->eh.i_audio_fcc, "channels", G_TYPE_INT, nuv->priv->eh.i_audio_channels, "layer", G_TYPE_INT, 3,	// fixme: magic number
   774 									   "mpegversion", G_TYPE_INT,
   775 									   nuv->priv->eh.i_version, NULL);
   776 
   777 	  nuv->priv->src_audio_pad =
   778 		gst_nuv_demux_create_pad(nuv, audio_caps, &audio_src_template,
   779 								 "audio_src");
   780 	  gst_caps_unref(audio_caps);
   781 	}
   782 
   783   gst_element_no_more_pads(GST_ELEMENT(nuv));
   784 }
   785 
   786 static gboolean
   787 gst_nuv_demux_validate_header(nuv_frame_header * h)
   788 {
   789   gboolean valid = FALSE;
   790  //g_usleep (1 * G_USEC_PER_SEC );
   791   switch (h->i_type)
   792 	{
   793 /*
   794     case 'V':
   795       if (h->i_compression == 0 ||
   796           h->i_compression == 1 ||
   797           h->i_compression == 2 ||
   798           h->i_compression == 'N' ||
   799           h->i_compression == 'L') {
   800          valid = TRUE;
   801       }
   802       break;
   803     case 'A':
   804       if (h->i_compression == 0 ||
   805           h->i_compression == 1 ||
   806           h->i_compression == 2 ||
   807           h->i_compression == 3 ||
   808           h->i_compression == 'F' ||
   809           h->i_compression == 'S' ||
   810           h->i_compression == 'N' ||
   811           h->i_compression == 'L') {
   812          valid = TRUE;
   813       }
   814       break;
   815     case 'S':
   816       if (h->i_compression == 'B' ||
   817           h->i_compression == 'A' ||
   818           h->i_compression == 'V' ||
   819           h->i_compression == 'S') {
   820          valid = TRUE;
   821       }
   822       break;
   823 */
   824 	case 'A':
   825 	case 'V':
   826 	case 'S':
   827 	case 'R':
   828 	case 'D':
   829 	case 'Q':
   830 	  valid = TRUE;
   831 	  break;
   832 	default:
   833 	  valid = FALSE;
   834 	}
   835 
   836   return valid;
   837 }
   838 
   839 static GstFlowReturn
   840 gst_nuv_demux_read_head_frame(GstNuvDemux * nuv)
   841 {
   842   GstFlowReturn ret = GST_FLOW_OK;
   843   gboolean valid = FALSE;
   844 
   845   do
   846 	{
   847 	  ret = gst_nuv_demux_frame_header_load(nuv, &nuv->priv->fh);
   848 	  if (ret != GST_FLOW_OK)
   849 		{
   850 		  return ret;
   851 		}
   852 
   853 	  if (gst_nuv_demux_validate_header(&nuv->priv->fh) == TRUE)
   854 		valid = TRUE;
   855 
   856 	}
   857   while (valid == FALSE);
   858 
   859   nuv->priv->state = GST_NUV_DEMUX_MOVI;
   860   return ret;
   861 }
   862 
   863 static gboolean
   864 gst_nuv_combine_flow(GstNuvDemux * nuv)
   865 {
   866   GstFlowReturn ret_video = nuv->priv->last_video_return;
   867   GstFlowReturn ret_audio = nuv->priv->last_audio_return;
   868 
   869   if ((ret_video != GST_FLOW_OK) && (ret_audio != GST_FLOW_OK))
   870 	return FALSE;
   871 
   872   if (GST_FLOW_IS_FATAL(ret_video))
   873 	return FALSE;
   874 
   875   if (GST_FLOW_IS_FATAL(ret_audio))
   876 	return FALSE;
   877 
   878   return TRUE;
   879 }
   880 
   881 static GstFlowReturn
   882 gst_nuv_demux_stream_data(GstNuvDemux * nuv)
   883 {
   884   GstFlowReturn ret = GST_FLOW_OK;
   885   GstPad *pad = NULL;
   886   guint64 timestamp;
   887   GstBuffer *buf = NULL;
   888   nuv_frame_header h;
   889 
   890   h = nuv->priv->fh;
   891 
   892   if (h.i_type == 'R')
   893 	{
   894 	  goto done;
   895 	}
   896 
   897   if (h.i_length > 0)
   898 	{
   899 	  ret = gst_nuv_demux_read_bytes(nuv, h.i_length, TRUE, &buf);
   900 	  if ((ret != GST_FLOW_OK) || (buf == NULL))
   901 		{
   902 		  goto done;
   903 		}
   904 
   905 	  if ((h.i_timecode < 0))
   906 		{
   907 		  h.i_timecode = 0;
   908 		 //goto done;
   909 		}
   910 
   911 	  timestamp = h.i_timecode * GST_MSECOND;
   912 	  GST_BUFFER_TIMESTAMP(buf) = timestamp;
   913 	}
   914   else
   915 	{
   916 	  goto done;
   917 	}
   918 
   919 
   920   switch (h.i_type)
   921 	{
   922 	case 'V':
   923 	  {
   924 		pad = nuv->priv->src_video_pad;
   925 
   926 		if (nuv->priv->new_video_segment)
   927 		  {
   928 
   929 		   /* send new segment event */
   930 			gst_pad_push_event(nuv->priv->src_video_pad,
   931 							   gst_event_new_new_segment(TRUE, 1.0,
   932 														 GST_FORMAT_TIME, 0,
   933 														 GST_CLOCK_TIME_NONE,
   934 														 0));
   935 
   936 			if (nuv->priv->time_start == GST_CLOCK_TIME_NONE)
   937 			  {
   938 				nuv->priv->time_start = timestamp;
   939 			  }
   940 			nuv->priv->new_video_segment = FALSE;
   941 		  }
   942 
   943 		break;
   944 	  }
   945 	case 'A':
   946 	  {
   947 		pad = nuv->priv->src_audio_pad;
   948 
   949 		if (nuv->priv->new_audio_segment)
   950 		  {
   951 		   /* send new segment event */
   952 			gst_pad_push_event(nuv->priv->src_audio_pad,
   953 							   gst_event_new_new_segment(TRUE, 1.0,
   954 														 GST_FORMAT_TIME, 0,
   955 														 GST_CLOCK_TIME_NONE,
   956 														 0));
   957 
   958 			if (nuv->priv->time_start == GST_CLOCK_TIME_NONE)
   959 			  {
   960 				nuv->priv->time_start = timestamp;
   961 			  }
   962 			nuv->priv->new_audio_segment = FALSE;
   963 		  }
   964 
   965 		break;
   966 	  }
   967 	case 'S':
   968 	  {
   969 		switch (h.i_compression)
   970 		  {
   971 		  case 'V':
   972 			GST_DEBUG_OBJECT(nuv, "sending new video segment: %d",
   973 							 h.i_timecode);
   974 			gst_pad_push_event(nuv->priv->src_video_pad,
   975 							   gst_event_new_new_segment(TRUE, 1.0,
   976 														 GST_FORMAT_TIME,
   977 														 h.i_timecode *
   978 														 GST_MSECOND,
   979 														 GST_CLOCK_TIME_NONE,
   980 														 0));
   981 			break;
   982 		  case 'A':
   983 			GST_DEBUG_OBJECT(nuv, "sending new audio segment: %d",
   984 							 h.i_timecode);
   985 			gst_pad_push_event(nuv->priv->src_audio_pad,
   986 							   gst_event_new_new_segment(TRUE, 1.0,
   987 														 GST_FORMAT_TIME, 0,
   988 														 GST_CLOCK_TIME_NONE,
   989 														 0));
   990 			break;
   991 		  default:
   992 			break;
   993 		  }
   994 		goto done;
   995 	  }
   996 	default:
   997 	  break;
   998 	}
   999 
  1000   if ((buf != NULL) && (pad != NULL))
  1001 	{
  1002 	 /* pushing the buffer */
  1003 	  gst_buffer_set_caps(buf, GST_PAD_CAPS(pad));
  1004 	  ret = gst_pad_push(pad, buf);
  1005 	  buf = NULL;
  1006 
  1007 	  if (ret != GST_FLOW_OK)
  1008 		{
  1009 		  GST_WARNING_OBJECT(nuv, "error: %d pushing on srcpad %s", ret,
  1010 							 gst_pad_get_name(pad));
  1011 
  1012 		  if (pad == nuv->priv->src_video_pad)
  1013 			{
  1014 			  nuv->priv->last_video_return = ret;
  1015 			}
  1016 		  else if (pad == nuv->priv->src_audio_pad)
  1017 			{
  1018 			  nuv->priv->last_audio_return = ret;
  1019 			}
  1020 
  1021 		 /* verify anothers flow if is necessary stop task */
  1022 		  if (gst_nuv_combine_flow(nuv) != FALSE)
  1023 			{
  1024 			  ret = GST_FLOW_OK;
  1025 			}
  1026 		  else
  1027 			{
  1028 			  GST_WARNING_OBJECT(nuv, "error: on push");
  1029 			}
  1030 
  1031 		}
  1032 	}
  1033 
  1034 done:
  1035   if (buf != NULL)
  1036 	{
  1037 	  gst_buffer_unref(buf);
  1038 	  buf = NULL;
  1039 	}
  1040   if (ret == GST_FLOW_OK)
  1041 	{
  1042 	  nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
  1043 	  memset(&nuv->priv->fh, 0, sizeof(nuv->priv->fh));
  1044 	}
  1045   return ret;
  1046 }
  1047 
  1048 static GstFlowReturn
  1049 gst_nuv_demux_stream_mpeg_data(GstNuvDemux * nuv)
  1050 {
  1051   GstFlowReturn ret = GST_FLOW_OK;
  1052 
  1053  /* ffmpeg extra data */
  1054   if (nuv->priv->new_file)
  1055 	{
  1056 	  GstBuffer *buf;
  1057 	  ret =
  1058 		gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE, &buf);
  1059 	  gst_buffer_unref(buf);
  1060 	}
  1061   else
  1062 	{
  1063 	  ret = gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE,
  1064 									 &nuv->priv->mpeg_buffer);
  1065 	}
  1066 
  1067   if ((ret != GST_FLOW_OK) || (nuv->priv->mpeg_buffer == NULL))
  1068 	{
  1069 	  return ret;
  1070 	}
  1071 
  1072   GST_BUFFER_SIZE(nuv->priv->mpeg_buffer) = nuv->priv->mpeg_data_size;
  1073   nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
  1074   return ret;
  1075 }
  1076 
  1077 static GstFlowReturn
  1078 gst_nuv_demux_stream_extra_data(GstNuvDemux * nuv)
  1079 {
  1080   GstFlowReturn ret = GST_FLOW_OK;
  1081 
  1082  /* Load 'D' */
  1083   nuv_frame_header h;
  1084 
  1085   if (nuv->priv->new_file)
  1086 	ret = gst_nuv_demux_frame_header_load(nuv, NULL);
  1087   else
  1088 	ret = gst_nuv_demux_frame_header_load(nuv, &h);
  1089 
  1090   if (ret != GST_FLOW_OK)
  1091 	return ret;
  1092 
  1093   if (h.i_type != 'D')
  1094 	{
  1095 	  GST_WARNING_OBJECT(nuv, "Unsuported rtjpeg");
  1096 	  return GST_FLOW_NOT_SUPPORTED;
  1097 	}
  1098 
  1099   if (h.i_length > 0)
  1100 	{
  1101 	  if (h.i_compression == 'F')
  1102 		{
  1103 		  nuv->priv->state = GST_NUV_DEMUX_MPEG_DATA;
  1104 		}
  1105 	  else
  1106 		{
  1107 		  GST_WARNING_OBJECT(nuv,
  1108 							 "only file with extended chunk are supported");
  1109 		  return GST_FLOW_NOT_SUPPORTED;
  1110 		}
  1111 	}
  1112   else
  1113 	{
  1114 	  nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
  1115 	}
  1116 
  1117   return ret;
  1118 }
  1119 
  1120 static GstFlowReturn
  1121 gst_nuv_demux_stream_extend_header_data(GstNuvDemux * nuv)
  1122 {
  1123   GstFlowReturn ret = GST_FLOW_OK;
  1124 
  1125   if (nuv->priv->new_file)
  1126 	ret = gst_nuv_demux_extended_header_load(nuv, NULL);
  1127   else
  1128 	{
  1129 	  ret = gst_nuv_demux_extended_header_load(nuv, &nuv->priv->eh);
  1130 	  if (ret != GST_FLOW_OK)
  1131 		return ret;
  1132 	  gst_nuv_demux_create_pads(nuv);
  1133 	}
  1134 
  1135   nuv->priv->state = GST_NUV_DEMUX_INDEX_CREATE;
  1136   return ret;
  1137 }
  1138 
  1139 static GstFlowReturn
  1140 gst_nuv_demux_stream_extend_header(GstNuvDemux * nuv)
  1141 {
  1142   GstBuffer *buf = NULL;
  1143   GstFlowReturn res = GST_FLOW_OK;
  1144 
  1145   res = gst_nuv_demux_read_bytes(nuv, 1, FALSE, &buf);
  1146   if ((res != GST_FLOW_OK) || (buf == NULL))
  1147 	{
  1148 	  if (buf != NULL)
  1149 		{
  1150 		  gst_buffer_unref(buf);
  1151 		}
  1152 	  return res;
  1153 	}
  1154 
  1155   if (buf->data[0] == 'X')
  1156 	{
  1157 	  gst_buffer_unref(buf);
  1158 	  buf = NULL;
  1159 	  nuv_frame_header h;
  1160 
  1161 	  res = gst_nuv_demux_frame_header_load(nuv, &h);
  1162 	  if (res != GST_FLOW_OK)
  1163 		return res;
  1164 
  1165 	  if (h.i_length != 512)
  1166 		{
  1167 		  return GST_FLOW_ERROR;
  1168 		}
  1169 	  nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
  1170 	}
  1171   else
  1172 	{
  1173 	  nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
  1174 	  g_object_unref(buf);
  1175 	  GST_ELEMENT_WARNING(nuv, STREAM, FAILED,
  1176 						  (_("incomplete NUV support")),
  1177 						  ("incomplete NUV support"));
  1178 	  return GST_FLOW_ERROR;
  1179 	}
  1180   return res;
  1181 }
  1182 
  1183 static void
  1184 gst_nuv_demux_create_seek_index(GstNuvDemux * nuv)
  1185 {
  1186   GstMessage *msg;
  1187   nuv_frame_header h;
  1188 
  1189   while (gst_nuv_demux_frame_header_load(nuv, &h) == GST_FLOW_OK)
  1190 	{
  1191 	  if ((h.i_type == 'V') && (h.i_keyframe == 0))
  1192 		{
  1193 		  frame_index_data *f = g_new0(frame_index_data, 1);
  1194 
  1195 		  f->offset = nuv->priv->offset - 12;
  1196 		  f->timecode = h.i_timecode * GST_MSECOND;
  1197 
  1198 		  nuv->priv->index = g_slist_append(nuv->priv->index, f);
  1199 		}
  1200 	  if (h.i_type != 'R')
  1201 		{
  1202 		  nuv->priv->offset += h.i_length;
  1203 		  if (h.i_type == 'A' || h.i_type == 'V')
  1204 			nuv->priv->duration_time = h.i_timecode * GST_MSECOND;
  1205 		}
  1206 	}
  1207   GST_DEBUG_OBJECT(nuv,
  1208 				   "CREATING INDEX: DONE : DURATION Bytes/Sec: %"
  1209 				   G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, nuv->priv->offset,
  1210 				   nuv->priv->duration_time);
  1211 
  1212   nuv->priv->duration_bytes = nuv->priv->offset;
  1213   nuv->priv->offset = nuv->priv->header_lengh;
  1214 
  1215   msg =
  1216 	gst_message_new_duration(GST_OBJECT(nuv), GST_FORMAT_TIME,
  1217 							 nuv->priv->duration_time);
  1218   gst_element_post_message(GST_ELEMENT(nuv), msg);
  1219 }
  1220 
  1221 static GstFlowReturn
  1222 gst_nuv_demux_play(GstPad * pad)
  1223 {
  1224   GstFlowReturn res = GST_FLOW_OK;
  1225   GstNuvDemux *nuv = GST_NUV_DEMUX(GST_PAD_PARENT(pad));
  1226 
  1227   switch (nuv->priv->state)
  1228 	{
  1229 	case GST_NUV_DEMUX_START:
  1230 	  res = gst_nuv_demux_stream_file_header(nuv);
  1231 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1232 		{
  1233 		  goto pause;
  1234 		}
  1235 	  break;
  1236 
  1237 	case GST_NUV_DEMUX_HEADER_DATA:
  1238 	  res = gst_nuv_demux_stream_header_data(nuv);
  1239 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1240 		{
  1241 		  goto pause;
  1242 		}
  1243 	  break;
  1244 
  1245 	case GST_NUV_DEMUX_EXTRA_DATA:
  1246 	  res = gst_nuv_demux_stream_extra_data(nuv);
  1247 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1248 		{
  1249 		  goto pause;
  1250 		}
  1251 	  break;
  1252 
  1253 	case GST_NUV_DEMUX_MPEG_DATA:
  1254 	  res = gst_nuv_demux_stream_mpeg_data(nuv);
  1255 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1256 		{
  1257 		  goto pause;
  1258 		}
  1259 	  break;
  1260 
  1261 	case GST_NUV_DEMUX_EXTEND_HEADER:
  1262 	  res = gst_nuv_demux_stream_extend_header(nuv);
  1263 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1264 		{
  1265 		  goto pause;
  1266 		}
  1267 	  break;
  1268 
  1269 	case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
  1270 	  res = gst_nuv_demux_stream_extend_header_data(nuv);
  1271 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1272 		{
  1273 		  goto pause;
  1274 		}
  1275 	 //store file header size
  1276 	  nuv->priv->header_lengh = nuv->priv->offset;
  1277 	  break;
  1278 
  1279 	case GST_NUV_DEMUX_INDEX_CREATE:
  1280 	  if ((nuv->priv->mode == NUV_PULL_MODE) && (!nuv->priv->new_file))
  1281 		{
  1282 		  gst_nuv_demux_create_seek_index(nuv);
  1283 		}
  1284 
  1285 	case GST_NUV_DEMUX_FRAME_HEADER:
  1286 	  res = gst_nuv_demux_read_head_frame(nuv);
  1287 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1288 		{
  1289 		  goto pause;
  1290 		}
  1291 	  break;
  1292 
  1293 	case GST_NUV_DEMUX_MOVI:
  1294 	  res = gst_nuv_demux_stream_data(nuv);
  1295 	  if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA))
  1296 		{
  1297 		  goto pause;
  1298 		}
  1299 	  break;
  1300 
  1301 	case GST_NUV_DEMUX_INVALID_DATA:
  1302 	  goto pause;
  1303 	  break;
  1304 	default:
  1305 	  g_assert_not_reached();
  1306 	}
  1307 
  1308   return GST_FLOW_OK;
  1309 
  1310 pause:
  1311   GST_LOG_OBJECT(nuv, "pausing task, reason %s", gst_flow_get_name(res));
  1312   gst_pad_pause_task(nuv->priv->sinkpad);
  1313 
  1314   if (res == GST_FLOW_ERROR_EOS)
  1315 	{
  1316 	  gst_nuv_demux_send_eos(nuv);
  1317 	  nuv->priv->eos = TRUE;
  1318 	  res = GST_FLOW_OK;
  1319 	}
  1320 
  1321   if (GST_FLOW_IS_FATAL(res))
  1322 	{
  1323 	  GST_ELEMENT_ERROR(nuv, STREAM, FAILED,
  1324 						(_("Internal data stream error.")),
  1325 						("streaming stopped, reason %s",
  1326 						 gst_flow_get_name(res)));
  1327 
  1328 	  gst_nuv_demux_send_eos(nuv);
  1329 	}
  1330   return res;
  1331 }
  1332 
  1333 static void
  1334 gst_nuv_demux_send_eos(GstNuvDemux * nuv)
  1335 {
  1336   gst_element_post_message(GST_ELEMENT(nuv),
  1337 						   gst_message_new_segment_done(GST_OBJECT(nuv),
  1338 														GST_FORMAT_TIME, -1));
  1339 
  1340   if (nuv->priv->src_video_pad)
  1341 	gst_pad_push_event(nuv->priv->src_video_pad, gst_event_new_eos());
  1342   if (nuv->priv->src_audio_pad)
  1343 	gst_pad_push_event(nuv->priv->src_audio_pad, gst_event_new_eos());
  1344 }
  1345 
  1346 static GstFlowReturn
  1347 gst_nuv_demux_read_bytes(GstNuvDemux * nuv, guint64 size, gboolean move,
  1348 						 GstBuffer ** buffer)
  1349 {
  1350   GstFlowReturn ret = GST_FLOW_OK;
  1351 
  1352   if (size == 0)
  1353 	{
  1354 	  return ret;
  1355 	}
  1356 
  1357   if (nuv->priv->mode == NUV_PULL_MODE)
  1358 	{
  1359 	  ret =
  1360 		gst_pad_pull_range(nuv->priv->sinkpad, nuv->priv->offset, size,
  1361 						   buffer);
  1362 	  if (ret == GST_FLOW_OK)
  1363 		{
  1364 		  if (move)
  1365 			{
  1366 			  nuv->priv->offset += size;
  1367 			}
  1368 		 /* got eos */
  1369 		}
  1370 	  else if (ret == GST_FLOW_UNEXPECTED)
  1371 		{
  1372 		  return GST_FLOW_ERROR_EOS;
  1373 		}
  1374 	}
  1375   else
  1376 	{
  1377 	  if (gst_adapter_available(nuv->priv->adapter) < size)
  1378 		{
  1379 		  nuv->priv->more_data = TRUE;
  1380 		  return GST_FLOW_ERROR_NO_DATA;
  1381 		}
  1382 	  if (move)
  1383 		{
  1384 		  *buffer = gst_adapter_take_buffer(nuv->priv->adapter, size);
  1385 		}
  1386 	  else
  1387 		{
  1388 		  guint8 *data = NULL;
  1389 		  data = (guint8 *) gst_adapter_peek(nuv->priv->adapter, size);
  1390 		  *buffer = gst_buffer_new();
  1391 		  gst_buffer_set_data(*buffer, data, size);
  1392 		}
  1393 	}
  1394   return ret;
  1395 }
  1396 
  1397 static GstFlowReturn
  1398 gst_nuv_demux_move_bytes(GstNuvDemux * nuv, guint64 size)
  1399 {
  1400   GstFlowReturn ret = GST_FLOW_OK;
  1401 
  1402   if (size == 0)
  1403 	{
  1404 	  return ret;
  1405 	}
  1406 
  1407   if (nuv->priv->mode == NUV_PULL_MODE)
  1408 	{
  1409 	  nuv->priv->offset += size;
  1410 	}
  1411   else
  1412 	{
  1413 	  if (gst_adapter_available(nuv->priv->adapter) < size)
  1414 		{
  1415 		  nuv->priv->more_data = TRUE;
  1416 		  return GST_FLOW_ERROR_NO_DATA;
  1417 		}
  1418 	  gst_adapter_flush(nuv->priv->adapter, size);
  1419 	}
  1420   return ret;
  1421 }
  1422 
  1423 static gboolean
  1424 gst_nuv_demux_sink_activate(GstPad * sinkpad)
  1425 {
  1426   gboolean res = TRUE;
  1427   GstNuvDemux *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
  1428 
  1429   if (gst_pad_check_pull_range(sinkpad))
  1430 	{
  1431 	  gst_adapter_clear(nuv->priv->adapter);
  1432 	  res = gst_pad_activate_pull(sinkpad, TRUE);
  1433 	}
  1434   else
  1435 	{
  1436 	  gst_adapter_clear(nuv->priv->adapter);
  1437 	  res = gst_pad_activate_push(sinkpad, TRUE);
  1438 	}
  1439 
  1440   g_object_unref(nuv);
  1441   return res;
  1442 }
  1443 
  1444 static gboolean
  1445 gst_nuv_demux_sink_activate_pull(GstPad * sinkpad, gboolean active)
  1446 {
  1447   GstNuvDemux *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
  1448 
  1449   if (active)
  1450 	{
  1451 	  GST_DEBUG_OBJECT(nuv, "activating pull function");
  1452 	  nuv->priv->mode = NUV_PULL_MODE;
  1453 	  gst_adapter_clear(nuv->priv->adapter);
  1454 
  1455 	  gst_pad_start_task(sinkpad, (GstTaskFunction) gst_nuv_demux_loop,
  1456 						 sinkpad);
  1457 	}
  1458   else
  1459 	{
  1460 	  GST_DEBUG_OBJECT(nuv, "deactivating pull function");
  1461 	  gst_pad_stop_task(sinkpad);
  1462 	}
  1463   gst_object_unref(nuv);
  1464 
  1465   return TRUE;
  1466 }
  1467 
  1468 static gboolean
  1469 gst_nuv_demux_sink_activate_push(GstPad * pad, gboolean active)
  1470 {
  1471   GstNuvDemux *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1472 
  1473   if (active)
  1474 	{
  1475 	  nuv->priv->mode = NUV_PUSH_MODE;
  1476 	  gst_adapter_clear(nuv->priv->adapter);
  1477 
  1478 	  GST_DEBUG_OBJECT(nuv, "activating push/chain function");
  1479 	}
  1480   else
  1481 	{
  1482 	  GST_DEBUG_OBJECT(nuv, "deactivating push/chain function");
  1483 	}
  1484 
  1485   gst_object_unref(nuv);
  1486 
  1487   return TRUE;
  1488 }
  1489 
  1490 static frame_index_data *
  1491 gst_nuv_demux_do_seek_index(GstNuvDemux * nuv, gint64 seek_pos,
  1492 							gint64 segment_stop, GstFormat format)
  1493 {
  1494   GSList *l;
  1495   frame_index_data *ret = NULL;
  1496 
  1497   if (nuv->priv->index == NULL)
  1498 	{
  1499 	  return NULL;
  1500 	}
  1501 
  1502  /* find keyframe closest to the requested position  */
  1503   for (l = nuv->priv->index; l != NULL; l = l->next)
  1504 	{
  1505 	  frame_index_data *f = (frame_index_data *) l->data;
  1506 	  gint64 pos = 0;
  1507 
  1508 	  if (format == GST_FORMAT_BYTES)
  1509 		{
  1510 		  pos = f->offset;
  1511 		}
  1512 	  else if (format == GST_FORMAT_TIME)
  1513 		{
  1514 		  pos = f->timecode;
  1515 		}
  1516 	  else
  1517 		{
  1518 		  return NULL;
  1519 		}
  1520 
  1521 	  if (pos >= seek_pos)
  1522 		{
  1523 		  ret = f;
  1524 		  break;
  1525 		}
  1526 
  1527 	  if ((segment_stop != -1) && (segment_stop != GST_CLOCK_TIME_NONE)
  1528 		  && (pos > segment_stop))
  1529 		{
  1530 		  break;
  1531 		}
  1532 	}
  1533 
  1534   return ret;
  1535 }
  1536 
  1537 static gboolean
  1538 gst_nuv_demux_do_seek(GstNuvDemux * nuv, GstEvent * event)
  1539 {
  1540   gdouble rate;
  1541   GstFormat format;
  1542   GstSeekFlags flags;
  1543   GstSeekType cur_type;
  1544   gint64 cur;
  1545   GstSeekType stop_type;
  1546   gint64 stop;
  1547   gboolean flush;
  1548   frame_index_data *entry;
  1549   gint64 segment_start;
  1550   gint64 segment_stop;
  1551   GstEvent *newsegment_event;
  1552 
  1553   if (nuv->priv->eos)
  1554 	{
  1555 	  return FALSE;
  1556 	}
  1557 
  1558   if (nuv->priv->mode == NUV_PUSH_MODE)
  1559 	{
  1560 	  return FALSE;
  1561 	}
  1562 
  1563 
  1564   gst_event_parse_seek(event, &rate, &format, &flags,
  1565 					   &cur_type, &cur, &stop_type, &stop);
  1566 
  1567 
  1568 
  1569 /*
  1570   if (format == GST_FORMAT_TIME) {
  1571     GST_DEBUG_OBJECT (nuv, "Can only seek on BYTES");
  1572     return FALSE;
  1573   }
  1574 */
  1575 
  1576   if (rate <= 0.0)
  1577 	{
  1578 	  GST_DEBUG_OBJECT(nuv, "Can only seek with positive rate");
  1579 	  return FALSE;
  1580 	}
  1581 
  1582   if (cur_type == GST_SEEK_TYPE_SET)
  1583 	{
  1584 	  GST_OBJECT_LOCK(nuv);
  1585 	  if (gst_nuv_demux_do_seek_index(nuv, cur, -1, format) == NULL)
  1586 		{
  1587 		  GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
  1588 		  GST_OBJECT_UNLOCK(nuv);
  1589 		  return FALSE;
  1590 		}
  1591 	  GST_OBJECT_UNLOCK(nuv);
  1592 	}
  1593 
  1594   flush = !!(flags & GST_SEEK_FLAG_FLUSH);
  1595 
  1596   if (flush)
  1597 	{
  1598 	  gst_pad_push_event(nuv->priv->sinkpad, gst_event_new_flush_start());
  1599 	  if (nuv->priv->src_video_pad != NULL)
  1600 		{
  1601 		  gst_pad_push_event(nuv->priv->src_video_pad,
  1602 							 gst_event_new_flush_start());
  1603 		}
  1604 
  1605 	  if (nuv->priv->src_audio_pad != NULL)
  1606 		{
  1607 		  gst_pad_push_event(nuv->priv->src_audio_pad,
  1608 							 gst_event_new_flush_start());
  1609 		}
  1610 	}
  1611   else
  1612 	{
  1613 	  gst_pad_pause_task(nuv->priv->sinkpad);
  1614 	}
  1615 
  1616   GST_PAD_STREAM_LOCK(nuv->priv->sinkpad);
  1617   GST_OBJECT_LOCK(nuv);
  1618 
  1619 
  1620   if (cur == GST_CLOCK_TIME_NONE)
  1621 	cur = 0;
  1622   if (stop == GST_CLOCK_TIME_NONE)
  1623 	stop = nuv->priv->duration_time;
  1624 
  1625   if (cur_type == GST_SEEK_TYPE_SET)
  1626 	segment_start = cur;
  1627   else if (cur_type == GST_SEEK_TYPE_CUR)
  1628 	segment_start = nuv->priv->segment_start + cur;
  1629   else
  1630 	segment_start = nuv->priv->segment_start;
  1631 
  1632   if (stop_type == GST_SEEK_TYPE_SET)
  1633 	segment_stop = stop;
  1634   else if (stop_type == GST_SEEK_TYPE_CUR)
  1635 	segment_stop = nuv->priv->segment_stop + stop;
  1636   else
  1637 	segment_stop = nuv->priv->segment_stop;
  1638 
  1639   segment_start = CLAMP(segment_start, 0, nuv->priv->duration_time);
  1640   segment_stop = CLAMP(segment_stop, 0, nuv->priv->duration_time);
  1641 
  1642   entry = gst_nuv_demux_do_seek_index(nuv, segment_start,
  1643 									  segment_stop, format);
  1644 
  1645   if (entry == NULL)
  1646 	{
  1647 	  GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
  1648 	  goto seek_error;
  1649 	}
  1650 
  1651   segment_start = entry->timecode;
  1652 
  1653   nuv->priv->segment_start = segment_start;
  1654   nuv->priv->segment_stop = segment_stop;
  1655 
  1656   GST_OBJECT_UNLOCK(nuv);
  1657 
  1658   if (!nuv->priv->eos)
  1659 	{
  1660 	  GstMessage *msg;
  1661 	  msg = gst_message_new_segment_start(GST_OBJECT(nuv), GST_FORMAT_TIME,
  1662 										  nuv->priv->segment_start);
  1663 
  1664 	  gst_element_post_message(GST_ELEMENT(nuv), msg);
  1665 	}
  1666 
  1667   GST_DEBUG_OBJECT(nuv,
  1668 				   "NEW SEGMENT START %" G_GUINT64_FORMAT ", STOP %"
  1669 				   G_GUINT64_FORMAT, segment_start, segment_stop);
  1670   newsegment_event =
  1671 	gst_event_new_new_segment(FALSE, rate, GST_FORMAT_TIME, segment_start,
  1672 							  segment_stop, segment_start);
  1673 
  1674 
  1675   if (flush)
  1676 	{
  1677 	  if (nuv->priv->src_video_pad != NULL)
  1678 		{
  1679 		  gst_pad_push_event(nuv->priv->src_video_pad,
  1680 							 gst_event_new_flush_stop());
  1681 		}
  1682 
  1683 	  if (nuv->priv->src_audio_pad != NULL)
  1684 		{
  1685 		  gst_pad_push_event(nuv->priv->src_audio_pad,
  1686 							 gst_event_new_flush_stop());
  1687 		}
  1688 
  1689 	  gst_pad_push_event(nuv->priv->sinkpad, gst_event_new_flush_stop());
  1690 	}
  1691 
  1692 
  1693   if (nuv->priv->src_video_pad != NULL)
  1694 	{
  1695 	  gst_pad_push_event(nuv->priv->src_video_pad,
  1696 						 gst_event_ref(newsegment_event));
  1697 	}
  1698   if (nuv->priv->src_audio_pad != NULL)
  1699 	{
  1700 	  gst_pad_push_event(nuv->priv->src_audio_pad,
  1701 						 gst_event_ref(newsegment_event));
  1702 	}
  1703 
  1704   gst_event_unref(newsegment_event);
  1705 
  1706   nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
  1707   nuv->priv->offset = entry->offset;
  1708 
  1709   gst_pad_start_task(nuv->priv->sinkpad, (GstTaskFunction) gst_nuv_demux_loop,
  1710 					 nuv->priv->sinkpad);
  1711 
  1712   GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
  1713   return TRUE;
  1714 
  1715 seek_error:
  1716   GST_DEBUG_OBJECT(nuv, "Got a seek error");
  1717   GST_OBJECT_UNLOCK(nuv);
  1718   GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
  1719   return FALSE;
  1720 
  1721 }
  1722 
  1723 static gboolean
  1724 gst_nuv_demux_srcpad_event(GstPad * pad, GstEvent * event)
  1725 {
  1726   gboolean res = FALSE;
  1727   GstNuvDemux *nuv;
  1728 
  1729   nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1730 
  1731   switch (GST_EVENT_TYPE(event))
  1732 	{
  1733 	case GST_EVENT_SEEK:
  1734 	  res = gst_nuv_demux_do_seek(nuv, event);
  1735 	  break;
  1736 	default:
  1737 	  res = FALSE;
  1738 	  break;
  1739 	}
  1740 
  1741   gst_object_unref(nuv);
  1742   return res;
  1743 }
  1744 
  1745 static gboolean
  1746 gst_nuv_demux_sink_event(GstPad * pad, GstEvent * event)
  1747 {
  1748   gboolean res = FALSE;
  1749   GstNuvDemux *nuv;
  1750 
  1751   nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1752 
  1753   switch (GST_EVENT_TYPE(event))
  1754 	{
  1755 	case GST_EVENT_NEWSEGMENT:
  1756 	  {
  1757 		gboolean update;
  1758 		gdouble rate;
  1759 		GstFormat format;
  1760 		gint64 start;
  1761 		gint64 stop;
  1762 		gint64 position;
  1763 
  1764 		gst_event_parse_new_segment(event, &update, &rate, &format, &start,
  1765 									&stop, &position);
  1766 		if ((format == GST_FORMAT_BYTES) && (start == 0))
  1767 		  {
  1768 			g_debug("NEW SEGMENT 0");
  1769 			if (nuv->priv->segment > 0)
  1770 			  {
  1771 				nuv->priv->new_file = TRUE;
  1772 				nuv->priv->state = GST_NUV_DEMUX_START;
  1773 				nuv->priv->offset = 0;
  1774 			  }
  1775 			nuv->priv->segment++;
  1776 
  1777 		   /*
  1778 		      newsegment_event = gst_event_new_new_segment (FALSE, rate,
  1779 		      GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE);
  1780 
  1781 		      gst_pad_push_event (nuv->priv->src_audio_pad, gst_event_ref (newsegment_event));
  1782 		      gst_pad_push_event (nuv->priv->src_video_pad, gst_event_ref (newsegment_event));
  1783 		      gst_event_unref (newsegment_event);
  1784 		    */
  1785 			res = gst_pad_event_default(pad, event);
  1786 		  }
  1787 		break;
  1788 	  }
  1789 	case GST_EVENT_CUSTOM_DOWNSTREAM:
  1790 	  {
  1791 	   /*
  1792 	      nuv->priv->new_file = TRUE;                  
  1793 	      nuv->priv->state = GST_NUV_DEMUX_START;
  1794 	      nuv->priv->offset = 0;
  1795 	    */
  1796 		GST_PAD_STREAM_LOCK(pad);
  1797 		gst_nuv_demux_reset(nuv);
  1798 		GST_PAD_STREAM_UNLOCK(pad);
  1799 
  1800 		res = gst_pad_event_default(pad, event);
  1801 		break;
  1802 	  }
  1803 	default:
  1804 	  res = gst_pad_event_default(pad, event);
  1805 	  break;
  1806 	}
  1807 
  1808   return res;
  1809 }
  1810 
  1811 static GstFlowReturn
  1812 gst_nuv_demux_chain(GstPad * pad, GstBuffer * buf)
  1813 {
  1814   GstFlowReturn ret = GST_FLOW_OK;
  1815   GstNuvDemux *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1816 
  1817   if (nuv->priv->mode != NUV_PUSH_MODE)
  1818 	return ret;
  1819 
  1820   gst_adapter_push(nuv->priv->adapter, buf);
  1821 
  1822   while ((ret == GST_FLOW_OK) && (nuv->priv->more_data == FALSE))
  1823 	{
  1824 	  ret = gst_nuv_demux_play(pad);
  1825 	}
  1826 
  1827   nuv->priv->more_data = FALSE;
  1828   gst_object_unref(nuv);
  1829 
  1830   return ret;
  1831 }
  1832 
  1833 static void
  1834 gst_nuv_demux_loop(GstPad * pad)
  1835 {
  1836   gst_nuv_demux_play(pad);
  1837 }
  1838 
  1839 static void
  1840 gst_nuv_demux_index_free(gpointer data, gpointer user_data)
  1841 {
  1842   g_free(data);
  1843 }
  1844 
  1845 static void
  1846 gst_nuv_demux_reset(GstNuvDemux * nuv)
  1847 {
  1848   nuv->priv->eos = FALSE;
  1849   nuv->priv->more_data = FALSE;
  1850   nuv->priv->state = GST_NUV_DEMUX_START;
  1851   nuv->priv->mode = NUV_PUSH_MODE;
  1852   nuv->priv->offset = 0;
  1853   nuv->priv->time_start = 0;
  1854   nuv->priv->time_qos = GST_CLOCK_TIME_NONE;
  1855   nuv->priv->duration_bytes = GST_CLOCK_TIME_NONE;
  1856   nuv->priv->duration_time = GST_CLOCK_TIME_NONE;
  1857   nuv->priv->last_video_return = GST_FLOW_OK;
  1858   nuv->priv->last_audio_return = GST_FLOW_OK;
  1859   nuv->priv->header_lengh = 0;
  1860   nuv->priv->segment_stop = GST_CLOCK_TIME_NONE;
  1861   nuv->priv->segment_start = GST_CLOCK_TIME_NONE;
  1862   nuv->priv->new_file = FALSE;
  1863 
  1864  //clear index list
  1865   g_slist_foreach(nuv->priv->index, gst_nuv_demux_index_free, NULL);
  1866   g_slist_free(nuv->priv->index);
  1867   nuv->priv->index = NULL;
  1868 
  1869   gst_adapter_clear(nuv->priv->adapter);
  1870 
  1871   if (nuv->priv->mpeg_buffer != NULL)
  1872 	{
  1873 	  gst_buffer_unref(nuv->priv->mpeg_buffer);
  1874 	  nuv->priv->mpeg_buffer = NULL;
  1875 	}
  1876 }
  1877 
  1878 static void
  1879 gst_nuv_demux_destoy_src_pad(GstNuvDemux * nuv)
  1880 {
  1881   if (nuv->priv->src_video_pad)
  1882 	{
  1883 	  gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_video_pad);
  1884 	  nuv->priv->src_video_pad = NULL;
  1885 	}
  1886 
  1887   if (nuv->priv->src_audio_pad)
  1888 	{
  1889 	  gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_audio_pad);
  1890 	  nuv->priv->src_audio_pad = NULL;
  1891 	}
  1892 }
  1893 
  1894 static GstStateChangeReturn
  1895 gst_nuv_demux_change_state(GstElement * element, GstStateChange transition)
  1896 {
  1897   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  1898 
  1899   g_debug("Nuvdemux state_change");
  1900   switch (transition)
  1901 	{
  1902 	case GST_STATE_CHANGE_NULL_TO_READY:
  1903 	  gst_nuv_demux_reset(GST_NUV_DEMUX(element));
  1904 	  gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
  1905 	  break;
  1906 	default:
  1907 	  break;
  1908 	}
  1909 
  1910   g_debug("Nuvdemux state_change: 1");
  1911 
  1912   ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
  1913   if (ret == GST_STATE_CHANGE_FAILURE)
  1914 	{
  1915 	  goto done;
  1916 	}
  1917 
  1918 
  1919   g_debug("Nuvdemux state_change: 2");
  1920 
  1921   switch (transition)
  1922 	{
  1923 	case GST_STATE_CHANGE_READY_TO_NULL:
  1924 	  gst_nuv_demux_reset(GST_NUV_DEMUX(element));
  1925 	  gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
  1926 	  break;
  1927 	default:
  1928 	  break;
  1929 	}
  1930 
  1931 
  1932   g_debug("Nuvdemux state_change: DONE");
  1933 
  1934 done:
  1935   return ret;
  1936 }
  1937 
  1938 #if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
  1939 GstBuffer *
  1940 gst_adapter_take_buffer(GstAdapter * adapter, guint nbytes)
  1941 {
  1942   GstBuffer *buffer;
  1943   GstBuffer *cur;
  1944   guint8 *data;
  1945 
  1946   g_return_val_if_fail(GST_IS_ADAPTER(adapter), NULL);
  1947   g_return_val_if_fail(nbytes > 0, NULL);
  1948 
  1949   GST_LOG_OBJECT(adapter, "taking buffer of %u bytes", nbytes);
  1950 
  1951  /* we don't have enough data, return NULL. This is unlikely
  1952   * as one usually does an _available() first instead of peeking a
  1953   * random size. */
  1954   if (G_UNLIKELY(nbytes > adapter->size))
  1955 	return NULL;
  1956 
  1957  /* our head buffer has enough data left, return it */
  1958   cur = adapter->buflist->data;
  1959   if (GST_BUFFER_SIZE(cur) >= nbytes + adapter->skip)
  1960 	{
  1961 	  GST_LOG_OBJECT(adapter, "providing buffer of %d bytes via sub-buffer",
  1962 					 nbytes);
  1963 	  buffer = gst_buffer_create_sub(cur, adapter->skip, nbytes);
  1964 
  1965 	  gst_adapter_flush(adapter, nbytes);
  1966 
  1967 	  return buffer;
  1968 	}
  1969 
  1970   data = gst_adapter_take(adapter, nbytes);
  1971   if (data == NULL)
  1972 	return NULL;
  1973 
  1974   buffer = gst_buffer_new();
  1975   GST_BUFFER_DATA(buffer) = data;
  1976   GST_BUFFER_MALLOCDATA(buffer) = data;
  1977   GST_BUFFER_SIZE(buffer) = nbytes;
  1978 
  1979   return buffer;
  1980 }
  1981 #endif
  1982 
  1983 static void
  1984 gst_nuv_typefind(GstTypeFind * tf, gpointer unused)
  1985 {
  1986   guint8 *data = gst_type_find_peek(tf, 0, 11);
  1987 
  1988   if (data)
  1989 	{
  1990 	  if (memcmp(data, "MythTVVideo", 11) == 0
  1991 		  || memcmp(data, "NuppelVideo", 11) == 0)
  1992 		{
  1993 		  gst_type_find_suggest(tf, GST_TYPE_FIND_MAXIMUM,
  1994 								gst_caps_new_simple("video/x-nuv", NULL));
  1995 		}
  1996 	}
  1997 }
  1998 
  1999 static gboolean
  2000 plugin_init(GstPlugin * plugin)
  2001 {
  2002   static gchar *exts[] = { "nuv", NULL };
  2003 #ifdef ENABLE_NLS
  2004   setlocale(LC_ALL, "");
  2005   bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
  2006 #endif /* ENABLE_NLS */
  2007 
  2008   if (!gst_element_register(plugin, "nuvdemux", GST_RANK_SECONDARY,
  2009 							GST_TYPE_NUV_DEMUX))
  2010 	{
  2011 	  return FALSE;
  2012 	}
  2013 
  2014   if (!gst_type_find_register(plugin, "video/x-nuv", GST_RANK_SECONDARY,
  2015 							  gst_nuv_typefind,
  2016 							  exts,
  2017 							  gst_caps_new_simple("video/x-nuv", NULL), NULL,
  2018 							  NULL))
  2019 	{
  2020 	  GST_WARNING("can't register typefind");
  2021 	  return FALSE;
  2022 	}
  2023 
  2024   return TRUE;
  2025 }
  2026 
  2027 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
  2028 				  GST_VERSION_MINOR,
  2029 				  "nuvdemux",
  2030 				  "Demuxes and muxes audio and video",
  2031 				  plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
  2032 				  GST_PACKAGE_ORIGIN)