gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c
author renatofilho
Fri Nov 10 19:21:45 2006 +0000 (2006-11-10)
branchtrunk
changeset 77 bca1fb717911
parent 75 761a8bbe4278
child 78 ac7e49c234d8
permissions -rw-r--r--
[svn r78] -fixed memory leak;
     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 
    55 #include "glib/gi18n.h"
    56 #include "gstnuvdemux.h"
    57 
    58 GST_DEBUG_CATEGORY_STATIC (nuvdemux_debug);
    59 #define GST_CAT_DEFAULT nuvdemux_debug
    60 
    61 
    62 #define GST_FLOW_ERROR_NO_DATA  -101
    63 
    64 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT);
    65 
    66 static const GstElementDetails gst_nuv_demux_details =
    67 GST_ELEMENT_DETAILS ("Nuv demuxer",
    68     "Codec/Demuxer",
    69     "Demultiplex a .nuv file into audio and video",
    70     "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
    71     "Rosfran Borges <rosfran.borges@indt.org.br>");
    72 
    73 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
    74     GST_PAD_SINK,
    75     GST_PAD_ALWAYS,
    76     GST_STATIC_CAPS ("video/x-nuv"));
    77 
    78 static GstStaticPadTemplate audio_src_template =
    79 GST_STATIC_PAD_TEMPLATE ("audio_src",
    80     GST_PAD_SRC,
    81     GST_PAD_SOMETIMES,
    82     GST_STATIC_CAPS_ANY);
    83 
    84 static GstStaticPadTemplate video_src_template =
    85 GST_STATIC_PAD_TEMPLATE ("video_src",
    86     GST_PAD_SRC,
    87     GST_PAD_SOMETIMES,
    88     GST_STATIC_CAPS_ANY);
    89 
    90 /* NUV Demux plug-in time-line functions */
    91 static void gst_nuv_demux_finalize (GObject * object);
    92 static GstStateChangeReturn gst_nuv_demux_change_state (GstElement * element,
    93     GstStateChange transition);
    94 static void gst_nuv_demux_loop (GstPad * pad);
    95 static GstFlowReturn gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf);
    96 static GstFlowReturn gst_nuv_demux_play (GstPad * pad);
    97 static gboolean gst_nuv_demux_sink_activate_pull (GstPad * sinkpad,
    98     gboolean active);
    99 static gboolean gst_nuv_demux_sink_activate_push (GstPad * pad, 
   100     gboolean active);
   101 static gboolean gst_nuv_demux_sink_activate (GstPad * sinkpad);
   102 static GstFlowReturn gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size,
   103     gboolean move, GstBuffer ** buffer);
   104 static void gst_nuv_demux_reset (GstNuvDemux * nuv);
   105 static void gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv);
   106 static void gst_nuv_demux_send_eos (GstNuvDemux * nuv);
   107 
   108 /* GObject methods */
   109 GST_BOILERPLATE (GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
   110 
   111 #if G_BYTE_ORDER == G_BIG_ENDIAN
   112 static inline gdouble
   113 _gdouble_swap_le_be (gdouble * d)
   114 {
   115   union
   116   {
   117     guint64 i;
   118     gdouble d;
   119   } u;
   120 
   121   u.d = *d;
   122   u.i = GUINT64_SWAP_LE_BE (u.i);
   123   return u.d;
   124 }
   125 
   126 #define READ_DOUBLE_FROM_LE(d) (_gdouble_swap_le_be((gdouble* ) d))
   127 #else /* G_BYTE_ORDER != G_BIG_ENDIAN */
   128 #define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
   129 #endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
   130 
   131 static void
   132 gst_nuv_demux_base_init (gpointer klass)
   133 {
   134   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   135 
   136   gst_element_class_add_pad_template (element_class,
   137       gst_static_pad_template_get (&audio_src_template));
   138 
   139   gst_element_class_add_pad_template (element_class,
   140       gst_static_pad_template_get (&video_src_template));
   141 
   142   gst_element_class_add_pad_template (element_class,
   143       gst_static_pad_template_get (&sink_template));
   144   gst_element_class_set_details (element_class, &gst_nuv_demux_details);
   145 }
   146 
   147 static void
   148 gst_nuv_demux_class_init (GstNuvDemuxClass * klass)
   149 {
   150   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
   151   GObjectClass *gobject_class = (GObjectClass *) klass;
   152 
   153   GST_DEBUG_CATEGORY_INIT (nuvdemux_debug, "nuvdemux",
   154       0, "Demuxer for NUV streams");
   155 
   156   parent_class = g_type_class_peek_parent (klass);
   157 
   158   gobject_class->finalize = gst_nuv_demux_finalize;
   159   gstelement_class->change_state = gst_nuv_demux_change_state;
   160 }
   161 
   162 static void
   163 gst_nuv_demux_init (GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
   164 {
   165   nuv->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
   166 
   167   gst_pad_set_activate_function (nuv->sinkpad, gst_nuv_demux_sink_activate);
   168 
   169   gst_pad_set_activatepull_function (nuv->sinkpad,
   170       gst_nuv_demux_sink_activate_pull);
   171 
   172   gst_pad_set_activatepush_function (nuv->sinkpad, 
   173       gst_nuv_demux_sink_activate_push);
   174 
   175   gst_pad_set_chain_function (nuv->sinkpad,
   176       GST_DEBUG_FUNCPTR (gst_nuv_demux_chain));
   177 
   178   gst_element_add_pad (GST_ELEMENT (nuv), nuv->sinkpad);
   179   
   180   gst_nuv_demux_index_init( &nuv->index_entries );
   181 
   182   nuv->adapter = NULL;
   183   nuv->mpeg_buffer = NULL;
   184   nuv->h = NULL;
   185   nuv->eh = NULL;
   186   nuv->fh = NULL;
   187   gst_nuv_demux_reset (nuv);
   188 }
   189 
   190 static void
   191 gst_nuv_demux_finalize (GObject * object)
   192 {
   193   GstNuvDemux *nuv = GST_NUV_DEMUX (object);
   194 
   195   if (nuv->mpeg_buffer != NULL) {
   196     gst_buffer_unref (nuv->mpeg_buffer);
   197   }
   198   
   199   if ( nuv->index_entries != NULL ) {
   200   	gst_nuv_demux_index_clean( &nuv->index_entries );
   201   	nuv->index_entries = NULL;
   202   }
   203 
   204   gst_nuv_demux_destoy_src_pad (nuv);
   205   gst_nuv_demux_reset (nuv);
   206   if (nuv->adapter != NULL) {
   207     gst_object_unref (nuv->adapter);
   208   }
   209   G_OBJECT_CLASS (parent_class)->finalize (object);
   210 }
   211 
   212 
   213 /* HeaderLoad:
   214  */
   215 static GstFlowReturn
   216 gst_nuv_demux_header_load (GstNuvDemux * nuv, nuv_header ** h_ret)
   217 {
   218   GstBuffer *buffer = NULL;
   219   GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 72, TRUE, &buffer);
   220 
   221   if (res != GST_FLOW_OK)
   222     return res;
   223 
   224   nuv_header *h = g_new0 (nuv_header, 1);
   225 
   226   memcpy (h->id, buffer->data, 12);
   227   memcpy (h->version, buffer->data + 12, 5);
   228   h->i_width = GST_READ_UINT32_LE (&buffer->data[20]);
   229   h->i_height = GST_READ_UINT32_LE (&buffer->data[24]);
   230   h->i_width_desired = GST_READ_UINT32_LE (&buffer->data[28]);
   231   h->i_height_desired = GST_READ_UINT32_LE (&buffer->data[32]);
   232   h->i_mode = GPOINTER_TO_INT (buffer->data[36]);
   233   h->d_aspect = READ_DOUBLE_FROM_LE (&buffer->data[40]);
   234   h->d_fps = READ_DOUBLE_FROM_LE (&buffer->data[48]);
   235   h->i_video_blocks = GST_READ_UINT32_LE (&buffer->data[56]);
   236   h->i_audio_blocks = GST_READ_UINT32_LE (&buffer->data[60]);
   237   h->i_text_blocks = GST_READ_UINT32_LE (&buffer->data[64]);
   238   h->i_keyframe_distance = GST_READ_UINT32_LE (&buffer->data[68]);
   239 
   240   GST_DEBUG_OBJECT (nuv,
   241       "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d", h->id,
   242       h->version, h->i_width, h->i_height, h->d_aspect, h->d_fps,
   243       h->i_video_blocks, h->i_audio_blocks, h->i_text_blocks,
   244       h->i_keyframe_distance);
   245 
   246   *h_ret = h;
   247   gst_buffer_unref (buffer);
   248   return res;
   249 }
   250 
   251 static GstFlowReturn
   252 gst_nuv_demux_stream_header_data (GstNuvDemux * nuv)
   253 {
   254   GstFlowReturn res = gst_nuv_demux_header_load (nuv, &nuv->h);
   255 
   256   if (res == GST_FLOW_OK)
   257     nuv->state = GST_NUV_DEMUX_EXTRA_DATA;
   258   return res;
   259 }
   260 
   261 /*
   262  * Read NUV file tag
   263  */
   264 static GstFlowReturn
   265 gst_nuv_demux_stream_file_header (GstNuvDemux * nuv)
   266 {
   267   GstFlowReturn res = GST_FLOW_OK;
   268   GstBuffer *file_header = NULL;
   269 
   270   res = gst_nuv_demux_read_bytes (nuv, 12, FALSE, &file_header);
   271   if (res != GST_FLOW_OK) {
   272     return res;
   273   } else {
   274     if (strncmp ((gchar *) file_header->data, "MythTVVideo", 11) ||
   275         strncmp ((gchar *) file_header->data, "NuppelVideo", 11)) {
   276       nuv->state = GST_NUV_DEMUX_HEADER_DATA;
   277     } else {
   278       GST_DEBUG_OBJECT (nuv, "error parsing file header");
   279       nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   280       res = GST_FLOW_ERROR;
   281     }
   282   }
   283   if (file_header != NULL) {
   284     gst_buffer_unref (file_header);
   285   }
   286   return res;
   287 }
   288 
   289 /* FrameHeaderLoad:
   290  */
   291 static GstFlowReturn
   292 gst_nuv_demux_frame_header_load (GstNuvDemux * nuv, nuv_frame_header ** h_ret)
   293 {
   294   unsigned char *data;
   295   nuv_frame_header *h;
   296   GstBuffer *buf = NULL;
   297 
   298   GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 12, TRUE, &buf);
   299 
   300   if (res != GST_FLOW_OK) {
   301     if (buf != NULL) {
   302       gst_buffer_unref (buf);
   303     }
   304     return res;
   305   }
   306 
   307   h = g_new0 (nuv_frame_header, 1);
   308   data = buf->data;
   309 
   310   h->i_type = GPOINTER_TO_INT (data[0]);
   311   h->i_compression = GPOINTER_TO_INT (data[1]);
   312   h->i_keyframe = GPOINTER_TO_INT (data[2]);
   313   h->i_filters = GPOINTER_TO_INT (data[3]);
   314   h->i_timecode = GST_READ_UINT32_LE (&data[4]);
   315   h->i_length = GST_READ_UINT32_LE (&data[8]);
   316   
   317   GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
   318       h->i_type,
   319       h->i_compression ? h->i_compression : ' ',
   320       h->i_keyframe ? h->i_keyframe : ' ',
   321       h->i_filters, h->i_timecode, h->i_length);
   322 
   323   *h_ret = h;
   324   gst_buffer_unref (buf);
   325   return GST_FLOW_OK;
   326 }
   327 
   328 static GstFlowReturn
   329 gst_nuv_demux_extended_header_load (GstNuvDemux * nuv,
   330     nuv_extended_header ** h_ret)
   331 {
   332   unsigned char *data;
   333   GstBuffer *buff = NULL;
   334   nuv_extended_header *h;
   335 
   336 
   337   GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 512, TRUE, &buff);
   338 
   339   if (res != GST_FLOW_OK) {
   340     if (buff != NULL) {
   341       gst_buffer_unref (buff);
   342     }
   343     return res;
   344   }
   345 
   346   h = g_new0 (nuv_extended_header, 1);
   347   data = buff->data;
   348   h->i_version = GST_READ_UINT32_LE (&data[0]);
   349   h->i_video_fcc = GST_MAKE_FOURCC (data[4], data[5], data[6], data[7]);
   350   h->i_audio_fcc = GST_MAKE_FOURCC (data[8], data[9], data[10], data[11]);
   351   h->i_audio_sample_rate = GST_READ_UINT32_LE (&data[12]);
   352   h->i_audio_bits_per_sample = GST_READ_UINT32_LE (&data[16]);
   353   h->i_audio_channels = GST_READ_UINT32_LE (&data[20]);
   354   h->i_audio_compression_ratio = GST_READ_UINT32_LE (&data[24]);
   355   h->i_audio_quality = GST_READ_UINT32_LE (&data[28]);
   356   h->i_rtjpeg_quality = GST_READ_UINT32_LE (&data[32]);
   357   h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE (&data[36]);
   358   h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE (&data[40]);
   359   h->i_lavc_bitrate = GST_READ_UINT32_LE (&data[44]);
   360   h->i_lavc_qmin = GST_READ_UINT32_LE (&data[48]);
   361   h->i_lavc_qmin = GST_READ_UINT32_LE (&data[52]);
   362   h->i_lavc_maxqdiff = GST_READ_UINT32_LE (&data[56]);
   363   h->i_seekable_offset = GST_READ_UINT64_LE (&data[60]);
   364   h->i_keyframe_adjust_offset = GST_READ_UINT64_LE (&data[68]);
   365 
   366   GST_DEBUG_OBJECT (nuv,
   367       "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d"
   368       "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld",
   369       h->i_version, (gchar *) & h->i_video_fcc, (gchar *) & h->i_audio_fcc,
   370       h->i_audio_sample_rate, h->i_audio_bits_per_sample, h->i_audio_channels,
   371       h->i_audio_compression_ratio, h->i_audio_quality, h->i_rtjpeg_quality,
   372       h->i_rtjpeg_luma_filter, h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate,
   373       h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff, h->i_seekable_offset,
   374       h->i_keyframe_adjust_offset);
   375 
   376   *h_ret = h;
   377   gst_buffer_unref (buff);
   378   return res;
   379 }
   380 
   381 static void
   382 gst_nuv_demux_create_pads (GstNuvDemux * nuv)
   383 {
   384   if (nuv->h->i_video_blocks != 0) {
   385     GstCaps *video_caps = NULL;
   386 
   387     nuv->src_video_pad =
   388         gst_pad_new_from_static_template (&video_src_template, "video_src");
   389 
   390     video_caps = gst_caps_new_simple ("video/x-divx",
   391         "divxversion", G_TYPE_INT, 4,
   392         "width", G_TYPE_INT, nuv->h->i_width,
   393         "height", G_TYPE_INT, nuv->h->i_height,
   394         "framerate", GST_TYPE_FRACTION, (gint) (nuv->h->d_fps * 1000.0f), 1000,
   395         "format", GST_TYPE_FOURCC, nuv->eh->i_video_fcc,
   396         "pixel-aspect-ratio", GST_TYPE_FRACTION,
   397         (gint) (nuv->h->d_aspect * 1000.0f), 1000, NULL);
   398 
   399     gst_pad_use_fixed_caps (nuv->src_video_pad);
   400     gst_pad_set_caps (nuv->src_video_pad, video_caps);
   401     gst_pad_set_active (nuv->src_video_pad, TRUE);
   402     gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
   403 
   404     gst_caps_unref (video_caps);
   405   }
   406 
   407   if (nuv->h->i_audio_blocks != 0) {
   408     GstCaps *audio_caps = NULL;
   409 
   410     nuv->src_audio_pad =
   411         gst_pad_new_from_static_template (&audio_src_template, "audio_src");
   412 
   413     audio_caps = gst_caps_new_simple ("audio/mpeg",
   414         "rate", G_TYPE_INT, nuv->eh->i_audio_sample_rate,
   415         "format", GST_TYPE_FOURCC, nuv->eh->i_audio_fcc,
   416         "channels", G_TYPE_INT, nuv->eh->i_audio_channels,
   417         "mpegversion", G_TYPE_INT, nuv->eh->i_version, NULL);
   418 
   419     gst_pad_use_fixed_caps (nuv->src_audio_pad);
   420     gst_pad_set_caps (nuv->src_audio_pad, audio_caps);
   421     gst_pad_set_active (nuv->src_audio_pad, TRUE);
   422     gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
   423     gst_caps_unref (audio_caps);
   424   }
   425 
   426   gst_element_no_more_pads (GST_ELEMENT (nuv));
   427 }
   428 
   429 static GstFlowReturn
   430 gst_nuv_demux_read_head_frame (GstNuvDemux * nuv)
   431 {
   432   GstFlowReturn ret = GST_FLOW_OK;
   433 
   434   if (nuv->fh != NULL) 
   435   {
   436     g_free (nuv->fh);
   437     nuv->fh = NULL;
   438   }
   439   
   440   ret = gst_nuv_demux_frame_header_load (nuv, &nuv->fh);
   441   if (ret != GST_FLOW_OK)
   442     return ret;
   443 
   444   nuv->state = GST_NUV_DEMUX_MOVI;
   445   return ret;
   446 }
   447 
   448 static GstFlowReturn
   449 gst_nuv_demux_stream_data (GstNuvDemux * nuv)
   450 {
   451   GstFlowReturn ret = GST_FLOW_OK;
   452   GstBuffer *buf = NULL;
   453   nuv_frame_header *h = nuv->fh;
   454 
   455   if (h->i_type == 'R')
   456     goto done;
   457     
   458   if (h->i_length > 0) {
   459 	  ret = gst_nuv_demux_read_bytes (nuv, h->i_length, TRUE, &buf);
   460 	  if (ret != GST_FLOW_OK)
   461 		  return ret;
   462 
   463       if ((h->i_type == 'V') || (h->i_type == 'A')) {
   464         if (h->i_timecode < 0) {
   465             nuv->last_time = 1;
   466             h->i_timecode = 0;
   467         }
   468         else if (nuv->last_time == 1)
   469         {
   470           nuv->last_time = 0;
   471           gst_pad_push_event (nuv->src_video_pad,
   472               gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, 
   473               		GST_CLOCK_TIME_NONE, 0));
   474 
   475           gst_pad_push_event (nuv->src_audio_pad,
   476               gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, 
   477               		GST_CLOCK_TIME_NONE, 0));
   478         }
   479 
   480         GST_BUFFER_TIMESTAMP (buf) = h->i_timecode * GST_MSECOND;
   481       }    
   482   }
   483 
   484   switch (h->i_type) {
   485     case 'V':
   486     {
   487       if (h->i_length == 0)
   488         break;
   489         
   490       if ( !gst_pad_is_linked( nuv->src_video_pad ) )
   491       	break;
   492       
   493       GST_BUFFER_SIZE (buf) = h->i_length;
   494       gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_video_pad));
   495       ret = gst_pad_push (nuv->src_video_pad, buf);
   496       if (ret != GST_FLOW_OK) {
   497         GST_WARNING_OBJECT (nuv, "error pushing on srcpad %s, is linked? = %d",
   498             gst_pad_get_name (nuv->src_video_pad), gst_pad_is_linked (nuv->src_video_pad));
   499       }
   500       break;
   501     }
   502     case 'A':
   503     {
   504       if (h->i_length == 0)
   505         break;
   506         
   507       if ( !gst_pad_is_linked( nuv->src_audio_pad ) )
   508       	break;
   509         
   510       GST_BUFFER_SIZE (buf) = h->i_length;
   511       gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_audio_pad));
   512       ret = gst_pad_push (nuv->src_audio_pad, buf);
   513       if (ret != GST_FLOW_OK) {
   514         GST_WARNING_OBJECT (nuv, "Error pushing on srcpad %s, is linked? = %d",
   515             gst_pad_get_name (nuv->src_audio_pad), gst_pad_is_linked (nuv->src_audio_pad));
   516       }
   517       break;
   518     }
   519     case 'S':
   520     {
   521       switch (h->i_compression) {
   522         case 'V':
   523 		  if ( !gst_pad_is_linked( nuv->src_video_pad ) )
   524 		    break;
   525 
   526           GST_DEBUG_OBJECT (nuv, "sending new video segment: %d", h->i_timecode);
   527           gst_pad_push_event (nuv->src_video_pad,
   528               gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, h->i_timecode * GST_MSECOND, 
   529               		GST_CLOCK_TIME_NONE, 0));
   530           break;
   531         case 'A':        
   532 		      if ( !gst_pad_is_linked( nuv->src_audio_pad ) )
   533 		      	break;
   534 
   535           GST_DEBUG_OBJECT (nuv, "sending new audio segment: %d", h->i_timecode);
   536           gst_pad_push_event (nuv->src_audio_pad,
   537               gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, 
   538               		GST_CLOCK_TIME_NONE, 0));
   539           break;
   540         default:
   541           break;
   542       }
   543       if (buf != NULL)
   544         gst_buffer_unref (buf);
   545     }
   546     default:
   547       if (buf != NULL)
   548         gst_buffer_unref (buf);
   549 
   550       break;
   551   }
   552 
   553 done:
   554   nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   555   g_free (nuv->fh);
   556   nuv->fh = NULL;
   557   return ret;
   558 }
   559 
   560 static GstFlowReturn
   561 gst_nuv_demux_stream_mpeg_data (GstNuvDemux * nuv)
   562 {
   563   GstFlowReturn ret = GST_FLOW_OK;
   564 
   565   /* ffmpeg extra data */
   566   ret =
   567       gst_nuv_demux_read_bytes (nuv, nuv->mpeg_data_size, TRUE,
   568       &nuv->mpeg_buffer);
   569   if (ret != GST_FLOW_OK) {
   570     return ret; 
   571   }
   572   GST_BUFFER_SIZE (nuv->mpeg_buffer) = nuv->mpeg_data_size;
   573   nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   574   return ret;
   575 }
   576 
   577 static GstFlowReturn
   578 gst_nuv_demux_stream_extra_data (GstNuvDemux * nuv)
   579 {
   580   GstFlowReturn ret = GST_FLOW_OK;
   581 
   582   /* Load 'D' */
   583   nuv_frame_header *h;
   584 
   585   ret = gst_nuv_demux_frame_header_load (nuv, &h);
   586   if (ret != GST_FLOW_OK)
   587     return ret;
   588 
   589   if (h->i_type != 'D') {
   590     g_free (h);
   591     return GST_FLOW_ERROR;
   592   }
   593 
   594   if (h->i_length > 0) {
   595     if (h->i_compression == 'F') {
   596       nuv->state = GST_NUV_DEMUX_MPEG_DATA;
   597     } else {
   598       g_free (h);
   599       return GST_FLOW_ERROR;
   600     }
   601   } else {
   602     nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   603   }
   604 
   605   g_free (h);
   606   h = NULL;
   607   return ret;
   608 }
   609 
   610 static GstFlowReturn
   611 gst_nuv_demux_stream_extend_header_data (GstNuvDemux * nuv)
   612 {
   613   GstFlowReturn ret = GST_FLOW_OK;
   614 
   615   ret = gst_nuv_demux_extended_header_load (nuv, &nuv->eh);
   616   if (ret != GST_FLOW_OK)
   617     return ret;
   618 
   619   gst_nuv_demux_create_pads (nuv);
   620   nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   621   return ret;
   622 }
   623 
   624 static GstFlowReturn
   625 gst_nuv_demux_stream_extend_header (GstNuvDemux * nuv)
   626 {
   627   GstBuffer *buf = NULL;
   628   GstFlowReturn res = GST_FLOW_OK;
   629 
   630   res = gst_nuv_demux_read_bytes (nuv, 1, FALSE, &buf);
   631   if (res != GST_FLOW_OK) {
   632     if (buf != NULL) {
   633       gst_buffer_unref (buf);
   634     }
   635     return res;
   636   }
   637 
   638   if (buf->data[0] == 'X') {
   639     gst_buffer_unref (buf);
   640     buf = NULL;
   641     nuv_frame_header *h = NULL;
   642 
   643     res = gst_nuv_demux_frame_header_load (nuv, &h);
   644     if (res != GST_FLOW_OK)
   645       return res;
   646 
   647     if (h->i_length != 512) {
   648       g_free (h);
   649       return GST_FLOW_ERROR;
   650     }
   651     g_free (h);
   652     h = NULL;
   653     nuv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
   654   } else {
   655     nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   656     g_object_unref (buf);
   657     GST_ELEMENT_WARNING (nuv, STREAM, FAILED,
   658         (_("incomplete NUV support")), ("incomplete NUV support"));
   659     return GST_FLOW_ERROR;
   660   }
   661   return res;
   662 }
   663 
   664 static GstFlowReturn
   665 gst_nuv_demux_play (GstPad * pad)
   666 {
   667   GstFlowReturn res = GST_FLOW_OK;
   668   GstNuvDemux *nuv = GST_NUV_DEMUX (GST_PAD_PARENT (pad));
   669 
   670   switch (nuv->state) {
   671     case GST_NUV_DEMUX_START:
   672       res = gst_nuv_demux_stream_file_header (nuv);
   673       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   674         goto pause;
   675       }
   676       if (nuv->state != GST_NUV_DEMUX_HEADER_DATA)
   677         break;
   678 
   679     case GST_NUV_DEMUX_HEADER_DATA:
   680       res = gst_nuv_demux_stream_header_data (nuv);
   681       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   682         goto pause;
   683       }
   684       if (nuv->state != GST_NUV_DEMUX_EXTRA_DATA)
   685         break;
   686 
   687     case GST_NUV_DEMUX_EXTRA_DATA:
   688       res = gst_nuv_demux_stream_extra_data (nuv);
   689       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   690         goto pause;
   691       }
   692       if (nuv->state != GST_NUV_DEMUX_MPEG_DATA)
   693         break;
   694 
   695     case GST_NUV_DEMUX_MPEG_DATA:
   696       res = gst_nuv_demux_stream_mpeg_data (nuv);
   697       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   698         goto pause;
   699       }
   700 
   701       if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER)
   702         break;
   703 
   704     case GST_NUV_DEMUX_EXTEND_HEADER:
   705       res = gst_nuv_demux_stream_extend_header (nuv);
   706       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   707         goto pause;
   708       }
   709       if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER_DATA)
   710         break;
   711 
   712     case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
   713       res = gst_nuv_demux_stream_extend_header_data (nuv);
   714       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   715         goto pause;
   716       }
   717 
   718       if (nuv->state != GST_NUV_DEMUX_FRAME_HEADER)
   719         break;
   720 
   721     case GST_NUV_DEMUX_FRAME_HEADER:
   722       res = gst_nuv_demux_read_head_frame (nuv);
   723       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   724         goto pause;
   725       }
   726       if (nuv->state != GST_NUV_DEMUX_MOVI)
   727         break;
   728 
   729     case GST_NUV_DEMUX_MOVI:
   730       res = gst_nuv_demux_stream_data (nuv);
   731       if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   732         goto pause;
   733       }
   734       break;
   735     case GST_NUV_DEMUX_INVALID_DATA:
   736       goto pause;
   737       break;
   738     default:
   739       g_assert_not_reached ();
   740   }
   741 
   742   GST_DEBUG_OBJECT (nuv, "state: %d res:%s", nuv->state,
   743       gst_flow_get_name (res));
   744 
   745   return GST_FLOW_OK;
   746 
   747 pause:
   748   GST_LOG_OBJECT (nuv, "pausing task, reason %s", gst_flow_get_name (res));
   749   gst_pad_pause_task (nuv->sinkpad);
   750   if (GST_FLOW_IS_FATAL (res)) {
   751     GST_ELEMENT_ERROR (nuv, STREAM, FAILED,
   752         (_("Internal data stream error.")),
   753         ("streaming stopped, reason %s", gst_flow_get_name (res)));
   754 
   755     gst_nuv_demux_send_eos (nuv);
   756   }
   757   return res;
   758 }
   759 
   760 static void
   761 gst_nuv_demux_send_eos (GstNuvDemux * nuv)
   762 {
   763   gst_element_post_message (GST_ELEMENT (nuv),
   764       gst_message_new_segment_done (GST_OBJECT (nuv), GST_FORMAT_TIME, -1));
   765 
   766   if (nuv->src_video_pad)
   767     gst_pad_push_event (nuv->src_video_pad, gst_event_new_eos ());
   768   if (nuv->src_audio_pad)
   769     gst_pad_push_event (nuv->src_audio_pad, gst_event_new_eos ());
   770 }
   771 
   772 static GstFlowReturn
   773 gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size, gboolean move,
   774     GstBuffer ** buffer)
   775 {
   776   GstFlowReturn ret = GST_FLOW_OK;
   777 
   778   if (size == 0) {
   779     *buffer = gst_buffer_new ();
   780     return ret;
   781   }
   782   
   783   if (nuv->mode == 0) {
   784     ret = gst_pad_pull_range (nuv->sinkpad, nuv->offset, size, buffer);
   785     if (ret == GST_FLOW_OK) {
   786         if (move) {
   787 		    nuv->offset += size;
   788 		}
   789       /* got eos */
   790     } else if (ret == GST_FLOW_UNEXPECTED) {
   791       if (buffer != NULL)
   792           gst_buffer_unref (buffer);
   793       
   794       gst_nuv_demux_send_eos (nuv);
   795       return GST_FLOW_WRONG_STATE;
   796     }
   797   } else {
   798     if (gst_adapter_available (nuv->adapter) < size)
   799       return GST_FLOW_ERROR_NO_DATA;
   800 
   801     if (move) {
   802       guint8 *data = NULL;
   803       data = (guint8 *) gst_adapter_take (nuv->adapter, size);
   804       *buffer = gst_buffer_new ();
   805       gst_buffer_set_data (*buffer, data, size);
   806     } else {
   807       guint8 *data = NULL;
   808       data = (guint8 *) gst_adapter_peek (nuv->adapter, size);
   809       *buffer = gst_buffer_new ();
   810       gst_buffer_set_data (*buffer, data, size);
   811     }
   812   }
   813   return ret;
   814 }
   815 
   816 static gboolean
   817 gst_nuv_demux_sink_activate (GstPad * sinkpad)
   818 {
   819   gboolean res = TRUE;
   820   GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
   821 
   822   if (gst_pad_check_pull_range (sinkpad)) {
   823     nuv->mode = 0;
   824     if (nuv->adapter) {
   825       gst_adapter_clear (nuv->adapter);
   826       g_object_unref (nuv->adapter);
   827       nuv->adapter = NULL;
   828     }
   829     res = gst_pad_activate_pull (sinkpad, TRUE);
   830   } else {
   831     nuv->mode = 1;
   832     if (nuv->adapter) {
   833       gst_adapter_clear (nuv->adapter);
   834     } else {
   835       nuv->adapter = gst_adapter_new ();
   836     }
   837     res = gst_pad_activate_push (sinkpad, TRUE);
   838   }
   839   g_object_unref (nuv);
   840   return res;
   841 }
   842 
   843 static gboolean
   844 gst_nuv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
   845 {
   846   GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (sinkpad));
   847 
   848   if (active) {
   849     gst_pad_start_task (sinkpad, (GstTaskFunction) gst_nuv_demux_loop, sinkpad);
   850   } else {
   851     gst_pad_stop_task (sinkpad);
   852   }
   853   gst_object_unref (nuv);
   854 
   855   return TRUE;
   856 }
   857 
   858 static gboolean
   859 gst_nuv_demux_sink_activate_push (GstPad * pad, gboolean active)
   860 {
   861   GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
   862 
   863   if (active) {
   864     GST_DEBUG_OBJECT (nuv, "activating push/chain function");
   865   } else {
   866     GST_DEBUG_OBJECT (nuv, "deactivating push/chain function");
   867   }
   868 
   869   gst_object_unref (nuv);
   870 
   871   return TRUE;
   872 }
   873 
   874 static GstFlowReturn
   875 gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf)
   876 {
   877   GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
   878 
   879   gst_adapter_push (nuv->adapter, buf);
   880 
   881   gst_object_unref (nuv);
   882 
   883   return gst_nuv_demux_play (pad);
   884 }
   885 
   886 static void
   887 gst_nuv_demux_loop (GstPad * pad)
   888 {
   889   gst_nuv_demux_play (pad);
   890 }
   891 
   892 static void
   893 gst_nuv_demux_reset (GstNuvDemux * nuv)
   894 {
   895   nuv->state = GST_NUV_DEMUX_START;
   896   nuv->mode = 0;
   897   nuv->offset = 0;
   898   nuv->last_time = 0;
   899 
   900   if (nuv->adapter != NULL)
   901     gst_adapter_clear (nuv->adapter);
   902 
   903   if (nuv->mpeg_buffer != NULL) {
   904     gst_buffer_unref (nuv->mpeg_buffer);
   905     nuv->mpeg_buffer = NULL;
   906   }
   907 
   908   g_free (nuv->h);
   909   nuv->h = NULL;
   910 
   911   g_free (nuv->eh);
   912   nuv->eh = NULL;
   913 
   914   g_free (nuv->fh);
   915   nuv->fh = NULL;
   916 }
   917 
   918 static void
   919 gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv)
   920 {
   921   if (nuv->src_video_pad) {
   922     gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
   923     nuv->src_video_pad = NULL;
   924   }
   925 
   926   if (nuv->src_audio_pad) {
   927     gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
   928     nuv->src_audio_pad = NULL;
   929   }
   930 }
   931 
   932 static GstStateChangeReturn
   933 gst_nuv_demux_change_state (GstElement * element, GstStateChange transition)
   934 {
   935   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
   936 
   937   switch (transition) {
   938     case GST_STATE_CHANGE_READY_TO_PAUSED:
   939       break;
   940     default:
   941       break;
   942   }
   943 
   944   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
   945   if (ret == GST_STATE_CHANGE_FAILURE)
   946     goto done;
   947 
   948   switch (transition) {
   949     case GST_STATE_CHANGE_PAUSED_TO_READY:
   950       gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (element));
   951       gst_nuv_demux_reset (GST_NUV_DEMUX (element));
   952       break;
   953     default:
   954       break;
   955   }
   956 
   957 done:
   958   return ret;
   959 }
   960 
   961 static gboolean
   962 plugin_init (GstPlugin * plugin)
   963 {
   964 #ifdef ENABLE_NLS
   965   setlocale (LC_ALL, "");
   966   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
   967 #endif /* ENABLE_NLS */
   968 
   969   if (!gst_element_register (plugin, "nuvdemux", GST_RANK_SECONDARY,
   970           GST_TYPE_NUV_DEMUX)) {
   971     return FALSE;
   972   }
   973   return TRUE;
   974 }
   975 
   976 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
   977     GST_VERSION_MINOR,
   978     "nuvdemux",
   979     "Demuxes and muxes audio and video",
   980     plugin_init, VERSION, "LGPL", "NuvDemux", "")