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