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