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