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