gst-gmyth/nuvdemux/gstnuvdemux.c
author renatofilho
Thu Nov 15 20:33:59 2007 +0000 (2007-11-15)
branchtrunk
changeset 880 22df7edb6e37
parent 822 c517a78bf7bf
child 885 5224e0d6e2b9
permissions -rw-r--r--
[svn r886] fixed audio sync
     1 /*
     2  * GStreamer Copyright (C) <2006> Renato Araujo Oliveira Filho
     3  * <renato.filho@indt.org.br> Rosfran Borges <rosfran.borges@indt.org.br>
     4  * This library is free software; you can redistribute it and/or modify it
     5  * under the terms of the GNU Library General Public License as published
     6  * by the Free Software Foundation; either version 2 of the License, or (at 
     7  * your option) any later version. This library is distributed in the hope 
     8  * that it will be useful, but WITHOUT ANY WARRANTY; without even the
     9  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
    10  * See the GNU Library General Public License for more details. You should 
    11  * have received a copy of the GNU Library General Public License along
    12  * with this library; if not, write to the Free Software Foundation, Inc.,
    13  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
    14  */
    15 /*
    16  * Element-Checklist-Version: 5 
    17  */
    18 
    19 /**
    20  * SECTION:element-nuvdemux
    21  *
    22  * <refsect2>
    23  * <para>
    24  * Demuxes an .nuv file into raw or compressed audio and/or video streams.
    25  * </para>
    26  * <para>
    27  * This element currently only supports pull-based scheduling.
    28  * </para>
    29  * <title>Example launch line</title>
    30  * <para>
    31  * <programlisting>
    32  * gst-launch filesrc test.nuv ! nuvdemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
    33  * </programlisting>
    34  * Play (parse and decode) an .nuv file and try to output it to
    35  * an automatically detected soundcard and videosink. If the NUV file contains
    36  * compressed audio or video data, this will only work if you have the
    37  * right decoder elements/plugins installed.
    38  * </para>
    39  * </refsect2>
    40  *
    41  */
    42 
    43 #ifdef HAVE_CONFIG_H
    44 #include "config.h"
    45 #endif
    46 
    47 #include <gst/gst.h>
    48 #include <gst/gsterror.h>
    49 #include <gst/gstplugin.h>
    50 #include <string.h>
    51 #include <math.h>
    52 
    53 #include "glib/gi18n.h"
    54 #include "gstnuvdemux.h"
    55 
    56 #define GST_NUV_DEMUX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_NUV_DEMUX, GstNuvDemuxPrivate))
    57 
    58 GST_DEBUG_CATEGORY_STATIC(nuvdemux_debug);
    59 #define GST_CAT_DEFAULT nuvdemux_debug
    60 #define GST_FLOW_ERROR_NO_DATA  -101
    61 #define GST_FLOW_ERROR_EOS	-102
    62 
    63 enum {
    64     NUV_PUSH_MODE = 0,
    65     NUV_PULL_MODE
    66 };
    67 
    68 GST_DEBUG_CATEGORY_EXTERN(GST_CAT_EVENT);
    69 
    70 static const GstElementDetails gst_nuv_demux_details =
    71 GST_ELEMENT_DETAILS("Nuv demuxer",
    72                     "Codec/Demuxer",
    73                     "Demultiplex a .nuv file into audio and video",
    74                     "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
    75                     "Rosfran Borges <rosfran.borges@indt.org.br>");
    76 
    77 
    78 /*
    79  * file header 
    80  */
    81 typedef struct {
    82     gchar           id[12];     /* "NuppelVideo\0" or "MythTVVideo\0" */
    83     gchar           version[5]; /* "x.xx\0" */
    84 
    85     gint            i_width;
    86     gint            i_height;
    87     gint            i_width_desired;
    88     gint            i_height_desired;
    89 
    90     gchar           i_mode;     /* P progressive, I interlaced */
    91 
    92     gdouble         d_aspect;   /* 1.0 squared pixel */
    93     gdouble         d_fps;
    94     // fps num/denom
    95     gint            i_fpsn;
    96     gint            i_fpsd;
    97 
    98     gint            i_video_blocks; /* 0 no video, -1 unknown */
    99     gint            i_audio_blocks;
   100     gint            i_text_blocks;
   101 
   102     gint            i_keyframe_distance;
   103 
   104 } nuv_header;
   105 
   106 /*
   107  * frame header 
   108  */
   109 typedef struct {
   110     gchar           i_type;     /* A: audio, V: video, S: sync; T: test R: 
   111                                  * Seekpoint (string:RTjjjjjjjj) D: Extra
   112                                  * data for codec */
   113     gchar           i_compression;  /* V: 0 uncompressed 1 RTJpeg 2
   114                                      * RTJpeg+lzo N black frame L copy
   115                                      * last A: 0 uncompressed (44100
   116                                      * 1-bits, 2ch) 1 lzo 2 layer 2 3
   117                                      * layer 3 F flac S shorten N null
   118                                      * frame loudless L copy last S: B
   119                                      * audio and vdeo sync point A audio
   120                                      * sync info (timecode == effective
   121                                      * dsp frequency*100) V next video
   122                                      * sync (timecode == next video frame
   123                                      * num) S audio,video,text correlation 
   124                                      */
   125     gchar           i_keyframe; /* 0 keyframe, else no no key frame */
   126     guint8          i_filters;  /* 0x01: gauss 5 pixel (8,2,2,2,2)/16
   127                                  * 0x02: gauss 5 pixel (8,1,1,1,1)/12
   128                                  * 0x04: cartoon filter */
   129 
   130     gint32          i_timecode; /* ms */
   131 
   132     gint            i_length;   /* V,A,T: length of following data S:
   133                                  * length of packet correl */
   134 } nuv_frame_header;
   135 
   136 
   137 /*
   138  * FIXME Not sure of this one 
   139  */
   140 typedef struct {
   141     gint            i_version;
   142     guint32         i_video_fcc;
   143 
   144     guint32         i_audio_fcc;
   145     gint            i_audio_sample_rate;
   146     gint            i_audio_bits_per_sample;
   147     gint            i_audio_channels;
   148     gint            i_audio_compression_ratio;
   149     gint            i_audio_quality;
   150     gint            i_rtjpeg_quality;
   151     gint            i_rtjpeg_luma_filter;
   152     gint            i_rtjpeg_chroma_filter;
   153     gint            i_lavc_bitrate;
   154     gint            i_lavc_qmin;
   155     gint            i_lavc_qmax;
   156     gint            i_lavc_maxqdiff;
   157     gint64          i_seekable_offset;
   158     gint64          i_keyframe_adjust_offset;
   159 
   160 } nuv_extended_header;
   161 
   162 typedef struct {
   163     gint64          timecode;
   164     gint64          offset;
   165 
   166 } frame_index_data;
   167 
   168 typedef enum {
   169     GST_NUV_DEMUX_START,
   170     GST_NUV_DEMUX_HEADER_DATA,
   171     GST_NUV_DEMUX_EXTRA_DATA,
   172     GST_NUV_DEMUX_MPEG_DATA,
   173     GST_NUV_DEMUX_EXTEND_HEADER,
   174     GST_NUV_DEMUX_EXTEND_HEADER_DATA,
   175     GST_NUV_DEMUX_INDEX_CREATE,
   176     GST_NUV_DEMUX_FRAME_HEADER,
   177     GST_NUV_DEMUX_MOVI,
   178     GST_NUV_DEMUX_INVALID_DATA
   179 } GstNuvDemuxState;
   180 
   181 struct _GstNuvDemuxPrivate {
   182     /*
   183      * used for indicate the mode 
   184      */
   185     guint           mode;
   186 
   187     /*
   188      * used on push mode 
   189      */
   190     GstAdapter     *adapter;
   191 
   192     /*
   193      * pads 
   194      */
   195     GstPad         *sinkpad;
   196     GstPad         *src_video_pad;
   197     GstPad         *src_audio_pad;
   198 
   199     /*
   200      * Flow control 
   201      */
   202     GstFlowReturn   last_video_return;
   203     GstFlowReturn   last_audio_return;
   204     gboolean        more_data;
   205     gboolean        eos;
   206     gboolean        new_file;
   207     guint           segment;
   208 
   209     /*
   210      * NUV decoding state 
   211      */
   212     GstNuvDemuxState state;
   213     guint64         offset;
   214 
   215     /*
   216      * duration information 
   217      */
   218     guint64         duration_bytes;
   219     guint64         duration_time;
   220     guint64         segment_stop;
   221     guint64         segment_start;
   222 
   223     /*
   224      * segment control info 
   225      */
   226     gboolean        new_audio_segment;
   227     gboolean        new_video_segment;
   228 
   229     /*
   230      * Mpeg ExtraData 
   231      */
   232     guint64         mpeg_data_size;
   233     GstBuffer      *mpeg_buffer;
   234 
   235     /*
   236      * Headers 
   237      */
   238     nuv_header      h;
   239     nuv_extended_header eh;
   240     nuv_frame_header fh;
   241 
   242     /*
   243      * anothers info 
   244      */
   245     guint64         header_lengh;
   246     gint64          time_start;
   247     gint64          time_diff;
   248     gint64          time_qos;
   249     guint64         last_frame_time;
   250     GSList         *index;
   251 };
   252 
   253 
   254 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE("sink",
   255                                                                     GST_PAD_SINK,
   256                                                                     GST_PAD_ALWAYS,
   257                                                                     GST_STATIC_CAPS
   258                                                                     ("video/x-nuv"));
   259 
   260 static GstStaticPadTemplate audio_src_template =
   261 GST_STATIC_PAD_TEMPLATE("audio_src",
   262                         GST_PAD_SRC,
   263                         GST_PAD_SOMETIMES,
   264                         GST_STATIC_CAPS_ANY);
   265 
   266 static GstStaticPadTemplate video_src_template =
   267 GST_STATIC_PAD_TEMPLATE("video_src",
   268                         GST_PAD_SRC,
   269                         GST_PAD_SOMETIMES,
   270                         GST_STATIC_CAPS_ANY);
   271 
   272 static void     gst_nuv_demux_dispose(GObject * object);
   273 static void     gst_nuv_demux_finalize(GObject * object);
   274 static GstStateChangeReturn gst_nuv_demux_change_state(GstElement *
   275                                                        element,
   276                                                        GstStateChange
   277                                                        transition);
   278 static void     gst_nuv_demux_loop(GstPad * pad);
   279 static GstFlowReturn gst_nuv_demux_chain(GstPad * pad, GstBuffer * buf);
   280 static GstFlowReturn gst_nuv_demux_play(GstPad * pad);
   281 static gboolean gst_nuv_demux_sink_activate_pull(GstPad * sinkpad,
   282                                                  gboolean active);
   283 static gboolean gst_nuv_demux_sink_activate_push(GstPad * pad,
   284                                                  gboolean active);
   285 static gboolean gst_nuv_demux_sink_activate(GstPad * sinkpad);
   286 static gboolean gst_nuv_demux_sink_event(GstPad * pad, GstEvent * event);
   287 static gboolean gst_nuv_demux_srcpad_event(GstPad * pad, GstEvent * event);
   288 static frame_index_data *gst_nuv_demux_do_seek_index(GstNuvDemux * nuv,
   289                                                      gint64 seek_pos,
   290                                                      gint64 segment_stop,
   291                                                      GstFormat format);
   292 
   293 
   294 static GstFlowReturn gst_nuv_demux_move_bytes(GstNuvDemux * nuv,
   295                                               guint64 size);
   296 static GstFlowReturn gst_nuv_demux_read_bytes(GstNuvDemux * nuv,
   297                                               guint64 size, gboolean move,
   298                                               GstBuffer ** buffer);
   299 static void     gst_nuv_demux_reset(GstNuvDemux * nuv);
   300 static void     gst_nuv_demux_destoy_src_pad(GstNuvDemux * nuv);
   301 static void     gst_nuv_demux_send_eos(GstNuvDemux * nuv);
   302 static void     gst_nuv_demux_create_seek_index(GstNuvDemux * nuv);
   303 
   304 
   305 #if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
   306 GstBuffer      *gst_adapter_take_buffer(GstAdapter * adapter,
   307                                         guint nbytes);
   308 #endif
   309 
   310 
   311 GST_BOILERPLATE(GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
   312 
   313 /******************************************************************************
   314  * Utils function
   315  ******************************************************************************/
   316 #if G_BYTE_ORDER == G_BIG_ENDIAN
   317 static inline   gdouble
   318 _gdouble_swap_le_be(gdouble * d)
   319 {
   320     union {
   321         guint64         i;
   322         gdouble         d;
   323     } u;
   324 
   325     u.d = *d;
   326     u.i = GUINT64_SWAP_LE_BE(u.i);
   327     return u.d;
   328 }
   329 
   330 #define READ_DOUBLE_FROM_LE(d) (_gdouble_swap_le_be((gdouble* ) d))
   331 #else                           /* G_BYTE_ORDER != G_BIG_ENDIAN */
   332 #define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
   333 #endif                          /* G_BYTE_ORDER != G_BIG_ENDIAN */
   334 
   335 static void
   336 double2fraction(double in, int *num, int *denom)
   337 {
   338     if (in == 29.97) {
   339         *num = 30000;
   340         *denom = 1001;
   341     } else if (in == 23.976) {
   342         *num = 24000;
   343         *denom = 1001;
   344     } else {
   345         *denom = 1;
   346         while (in - floor(in) >= 0.1) {
   347             *denom *= 10;
   348             in *= 10.0;
   349         }
   350         *num = (int) floor(in);
   351     }
   352 }
   353 
   354 /*
   355  * GObject Functions 
   356  */
   357 
   358 static void
   359 gst_nuv_demux_base_init(gpointer klass)
   360 {
   361     GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
   362 
   363     gst_element_class_add_pad_template(element_class,
   364                                        gst_static_pad_template_get
   365                                        (&audio_src_template));
   366 
   367     gst_element_class_add_pad_template(element_class,
   368                                        gst_static_pad_template_get
   369                                        (&video_src_template));
   370 
   371     gst_element_class_add_pad_template(element_class,
   372                                        gst_static_pad_template_get
   373                                        (&sink_template));
   374     gst_element_class_set_details(element_class, &gst_nuv_demux_details);
   375 }
   376 
   377 static void
   378 gst_nuv_demux_class_init(GstNuvDemuxClass * klass)
   379 {
   380     GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass);
   381     GObjectClass   *gobject_class = (GObjectClass *) klass;
   382 
   383     GST_DEBUG_CATEGORY_INIT(nuvdemux_debug, "nuvdemux",
   384                             0, "Demuxer for NUV streams");
   385 
   386     parent_class = g_type_class_peek_parent(klass);
   387 
   388     gobject_class->dispose = gst_nuv_demux_dispose;
   389     gobject_class->finalize = gst_nuv_demux_finalize;
   390     gstelement_class->change_state = gst_nuv_demux_change_state;
   391 
   392     g_type_class_add_private(gobject_class, sizeof(GstNuvDemuxPrivate));
   393 }
   394 
   395 static void
   396 gst_nuv_demux_init(GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
   397 {
   398     nuv->priv = GST_NUV_DEMUX_GET_PRIVATE(nuv);
   399     nuv->priv->sinkpad =
   400         gst_pad_new_from_static_template(&sink_template, "sink");
   401 
   402     /*
   403      * creating adapter 
   404      */
   405     nuv->priv->mode = NUV_PUSH_MODE;
   406     nuv->priv->adapter = gst_adapter_new();
   407 
   408     nuv->priv->new_audio_segment = TRUE;
   409     nuv->priv->new_video_segment = TRUE;
   410 
   411     gst_pad_set_activate_function(nuv->priv->sinkpad,
   412                                   gst_nuv_demux_sink_activate);
   413     gst_pad_set_activatepull_function(nuv->priv->sinkpad,
   414                                       gst_nuv_demux_sink_activate_pull);
   415     gst_pad_set_activatepush_function(nuv->priv->sinkpad,
   416                                       gst_nuv_demux_sink_activate_push);
   417     gst_pad_set_chain_function(nuv->priv->sinkpad,
   418                                GST_DEBUG_FUNCPTR(gst_nuv_demux_chain));
   419     gst_pad_set_event_function(nuv->priv->sinkpad,
   420                                GST_DEBUG_FUNCPTR
   421                                (gst_nuv_demux_sink_event));
   422 
   423 
   424     gst_element_add_pad(GST_ELEMENT(nuv), nuv->priv->sinkpad);
   425 
   426 }
   427 
   428 static void
   429 gst_nuv_demux_dispose(GObject * object)
   430 {
   431     GstNuvDemux    *nuv = GST_NUV_DEMUX(object);
   432 
   433 
   434     if (nuv->priv->mpeg_buffer != NULL) {
   435         gst_buffer_unref(nuv->priv->mpeg_buffer);
   436     }
   437 
   438     gst_nuv_demux_reset(GST_NUV_DEMUX(object));
   439     gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(object));
   440 
   441     if (nuv->priv->adapter != NULL) {
   442         gst_object_unref(nuv->priv->adapter);
   443     }
   444 }
   445 
   446 static void
   447 gst_nuv_demux_finalize(GObject * object)
   448 {
   449     G_OBJECT_CLASS(parent_class)->finalize(object);
   450 }
   451 
   452 
   453 /*
   454  * HeaderLoad: 
   455  */
   456 static          GstFlowReturn
   457 gst_nuv_demux_header_load(GstNuvDemux * nuv, nuv_header * h)
   458 {
   459     GstBuffer      *buffer = NULL;
   460     GstFlowReturn   res = gst_nuv_demux_read_bytes(nuv, 72, TRUE, &buffer);
   461 
   462     if ((res != GST_FLOW_OK) || (buffer == NULL)) {
   463         goto done;
   464     }
   465 
   466     if (h != NULL) {
   467         memcpy(h->id, buffer->data, 12);
   468         memcpy(h->version, buffer->data + 12, 5);
   469         h->i_width = GST_READ_UINT32_LE(&buffer->data[20]);
   470         h->i_height = GST_READ_UINT32_LE(&buffer->data[24]);
   471         h->i_width_desired = GST_READ_UINT32_LE(&buffer->data[28]);
   472         h->i_height_desired = GST_READ_UINT32_LE(&buffer->data[32]);
   473         h->i_mode = GPOINTER_TO_INT(buffer->data[36]);
   474         h->d_aspect = READ_DOUBLE_FROM_LE(&buffer->data[40]);
   475         h->d_fps = READ_DOUBLE_FROM_LE(&buffer->data[48]);
   476         /*
   477          * get the num and denom values from fps 
   478          */
   479         double2fraction(h->d_fps, &h->i_fpsn, &h->i_fpsd);
   480         h->i_video_blocks = GST_READ_UINT32_LE(&buffer->data[56]);
   481         h->i_audio_blocks = GST_READ_UINT32_LE(&buffer->data[60]);
   482         h->i_text_blocks = GST_READ_UINT32_LE(&buffer->data[64]);
   483         h->i_keyframe_distance = GST_READ_UINT32_LE(&buffer->data[68]);
   484 
   485         GST_DEBUG_OBJECT(nuv,
   486                          "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d",
   487                          h->id, h->version, h->i_width, h->i_height,
   488                          h->d_aspect, h->d_fps, h->i_video_blocks,
   489                          h->i_audio_blocks, h->i_text_blocks,
   490                          h->i_keyframe_distance);
   491     }
   492 
   493   done:
   494     if (buffer != NULL) {
   495         gst_buffer_unref(buffer);
   496         buffer = NULL;
   497     }
   498     return res;
   499 }
   500 
   501 static          GstFlowReturn
   502 gst_nuv_demux_stream_header_data(GstNuvDemux * nuv)
   503 {
   504     GstFlowReturn   res;
   505 
   506     if (nuv->priv->new_file)
   507         res = gst_nuv_demux_header_load(nuv, NULL);
   508     else
   509         res = gst_nuv_demux_header_load(nuv, &nuv->priv->h);
   510 
   511     if (res == GST_FLOW_OK)
   512         nuv->priv->state = GST_NUV_DEMUX_EXTRA_DATA;
   513     return res;
   514 }
   515 
   516 /*
   517  * Read NUV file tag
   518  */
   519 static          GstFlowReturn
   520 gst_nuv_demux_stream_file_header(GstNuvDemux * nuv)
   521 {
   522     GstFlowReturn   res = GST_FLOW_OK;
   523     GstBuffer      *file_header = NULL;
   524 
   525     res = gst_nuv_demux_read_bytes(nuv, 12, FALSE, &file_header);
   526     if (res == GST_FLOW_OK) {
   527         if (strncmp((gchar *) file_header->data, "MythTVVideo", 11) ||
   528             strncmp((gchar *) file_header->data, "NuppelVideo", 11)) {
   529             nuv->priv->state = GST_NUV_DEMUX_HEADER_DATA;
   530         } else {
   531             GST_DEBUG_OBJECT(nuv, "error parsing file header");
   532             nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
   533             res = GST_FLOW_ERROR;
   534         }
   535     }
   536 
   537     if (file_header != NULL) {
   538         gst_buffer_unref(file_header);
   539         file_header = NULL;
   540     }
   541     return res;
   542 }
   543 
   544 /*
   545  * FrameHeaderLoad: 
   546  */
   547 static          GstFlowReturn
   548 gst_nuv_demux_frame_header_load(GstNuvDemux * nuv, nuv_frame_header * h)
   549 {
   550     unsigned char  *data;
   551     GstBuffer      *buf = NULL;
   552 
   553     GstFlowReturn   res = gst_nuv_demux_read_bytes(nuv, 12, TRUE, &buf);
   554 
   555     if ((res != GST_FLOW_OK) || (buf == NULL)) {
   556         goto done;
   557     }
   558 
   559     if (h == NULL)
   560         goto done;
   561 
   562     data = buf->data;
   563 
   564     h->i_type = GPOINTER_TO_INT(data[0]);
   565     h->i_compression = GPOINTER_TO_INT(data[1]);
   566     h->i_keyframe = GPOINTER_TO_INT(data[2]);
   567     h->i_filters = GPOINTER_TO_INT(data[3]);
   568     h->i_timecode = GST_READ_UINT32_LE(&data[4]);
   569     h->i_length = GST_READ_UINT32_LE(&data[8]);
   570 
   571     GST_DEBUG_OBJECT(nuv,
   572                      "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
   573                      h->i_type, h->i_compression ? h->i_compression : ' ',
   574                      h->i_keyframe ? h->i_keyframe : ' ', h->i_filters,
   575                      h->i_timecode, h->i_length);
   576 
   577   done:
   578     if (buf != NULL) {
   579         gst_buffer_unref(buf);
   580         buf = NULL;
   581     }
   582 
   583     return res;
   584 }
   585 
   586 static          GstFlowReturn
   587 gst_nuv_demux_extended_header_load(GstNuvDemux * nuv,
   588                                    nuv_extended_header * h)
   589 {
   590     unsigned char  *data;
   591     GstBuffer      *buff = NULL;
   592 
   593     GstFlowReturn   res = gst_nuv_demux_read_bytes(nuv, 512, TRUE, &buff);
   594 
   595     if ((res != GST_FLOW_OK) || (buff == NULL)) {
   596         goto done;
   597     }
   598 
   599     if (h == NULL)
   600         goto done;
   601 
   602     data = buff->data;
   603     h->i_version = GST_READ_UINT32_LE(&data[0]);
   604     h->i_video_fcc = GST_MAKE_FOURCC(data[4], data[5], data[6], data[7]);
   605     h->i_audio_fcc = GST_MAKE_FOURCC(data[8], data[9], data[10], data[11]);
   606     h->i_audio_sample_rate = GST_READ_UINT32_LE(&data[12]);
   607     h->i_audio_bits_per_sample = GST_READ_UINT32_LE(&data[16]);
   608     h->i_audio_channels = GST_READ_UINT32_LE(&data[20]);
   609     h->i_audio_compression_ratio = GST_READ_UINT32_LE(&data[24]);
   610     h->i_audio_quality = GST_READ_UINT32_LE(&data[28]);
   611     h->i_rtjpeg_quality = GST_READ_UINT32_LE(&data[32]);
   612     h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE(&data[36]);
   613     h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE(&data[40]);
   614     h->i_lavc_bitrate = GST_READ_UINT32_LE(&data[44]);
   615     h->i_lavc_qmin = GST_READ_UINT32_LE(&data[48]);
   616     h->i_lavc_qmin = GST_READ_UINT32_LE(&data[52]);
   617     h->i_lavc_maxqdiff = GST_READ_UINT32_LE(&data[56]);
   618     h->i_seekable_offset = GST_READ_UINT64_LE(&data[60]);
   619     h->i_keyframe_adjust_offset = GST_READ_UINT64_LE(&data[68]);
   620 
   621     GST_DEBUG_OBJECT(nuv,
   622                      "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d"
   623                      "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld",
   624                      h->i_version, (gchar *) & h->i_video_fcc,
   625                      (gchar *) & h->i_audio_fcc, h->i_audio_sample_rate,
   626                      h->i_audio_bits_per_sample, h->i_audio_channels,
   627                      h->i_audio_compression_ratio, h->i_audio_quality,
   628                      h->i_rtjpeg_quality, h->i_rtjpeg_luma_filter,
   629                      h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate,
   630                      h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff,
   631                      h->i_seekable_offset, h->i_keyframe_adjust_offset);
   632 
   633   done:
   634     if (buff != NULL) {
   635         gst_buffer_unref(buff);
   636         buff = NULL;
   637     }
   638     return res;
   639 }
   640 
   641 
   642 /*
   643  * Query Functions 
   644  */
   645 static const GstQueryType *
   646 gst_nuv_demux_get_src_query_types(GstPad * pad)
   647 {
   648     static const GstQueryType src_types[] = {
   649         GST_QUERY_POSITION,
   650         GST_QUERY_DURATION,
   651         0
   652     };
   653 
   654     return src_types;
   655 }
   656 
   657 static          gboolean
   658 gst_nuv_demux_handle_src_query(GstPad * pad, GstQuery * query)
   659 {
   660     gboolean        res = FALSE;
   661     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
   662 
   663 
   664     switch (GST_QUERY_TYPE(query)) {
   665     case GST_QUERY_POSITION:
   666         {
   667             GstFormat       format;
   668             gst_query_parse_position(query, &format, NULL);
   669             switch (format) {
   670             case GST_FORMAT_TIME:
   671                 if (GST_CLOCK_TIME_IS_VALID(nuv->priv->last_frame_time)) {
   672                     gst_query_set_position(query, GST_FORMAT_TIME,
   673                                            nuv->priv->last_frame_time);
   674                     res = TRUE;
   675                 }
   676                 break;
   677             default:
   678                 break;
   679             }
   680             break;
   681         }
   682     case GST_QUERY_DURATION:
   683         {
   684             GstFormat       format;
   685             gst_query_parse_duration(query, &format, NULL);
   686             switch (format) {
   687             case GST_FORMAT_TIME:
   688                 if (nuv->priv->duration_time != GST_CLOCK_TIME_NONE) {
   689                     gst_query_set_duration(query, GST_FORMAT_TIME,
   690                                            nuv->priv->duration_time);
   691                     res = TRUE;
   692                 }
   693                 break;
   694             default:
   695                 break;
   696             }
   697             break;
   698         }
   699     default:
   700         break;
   701     }
   702 
   703     if (res == FALSE) {
   704         res = gst_pad_query_default(pad, query);
   705     }
   706 
   707     gst_object_unref(nuv);
   708     return res;
   709 }
   710 
   711 static GstPad  *
   712 gst_nuv_demux_create_pad(GstNuvDemux * nuv, GstCaps * caps,
   713                          GstStaticPadTemplate * template,
   714                          const gchar * name)
   715 {
   716     GstPad         *pad = NULL;
   717     pad = gst_pad_new_from_static_template(template, name);
   718     gst_pad_set_caps(pad, caps);
   719     gst_pad_set_active(pad, TRUE);
   720     gst_pad_use_fixed_caps(pad);
   721     gst_element_add_pad(GST_ELEMENT(nuv), pad);
   722 
   723     gst_pad_set_event_function(pad,
   724                                GST_DEBUG_FUNCPTR
   725                                (gst_nuv_demux_srcpad_event));
   726 
   727     gst_pad_set_query_type_function(pad,
   728                                     GST_DEBUG_FUNCPTR
   729                                     (gst_nuv_demux_get_src_query_types));
   730 
   731     gst_pad_set_query_function(pad,
   732                                GST_DEBUG_FUNCPTR
   733                                (gst_nuv_demux_handle_src_query));
   734 
   735 
   736     return pad;
   737 }
   738 
   739 static void
   740 gst_nuv_demux_create_pads(GstNuvDemux * nuv)
   741 {
   742     if ((nuv->priv->src_video_pad != NULL) || 
   743         (nuv->priv->src_audio_pad != NULL)) {
   744         return;
   745     }
   746 
   747     if (nuv->priv->h.i_video_blocks != 0){
   748         GstCaps *video_caps = NULL;
   749 
   750         video_caps = gst_caps_new_simple("video/x-divx",
   751                                          "divxversion", G_TYPE_INT, 4,
   752                                          "width", G_TYPE_INT,
   753                                          nuv->priv->h.i_width, "height",
   754                                          G_TYPE_INT, nuv->priv->h.i_height,
   755                                          "framerate", GST_TYPE_FRACTION,
   756                                          nuv->priv->h.i_fpsn,
   757                                          nuv->priv->h.i_fpsd, "format",
   758                                          GST_TYPE_FOURCC,
   759                                          nuv->priv->eh.i_video_fcc,
   760                                          "pixel-aspect-ratio",
   761                                          GST_TYPE_FRACTION,
   762                                          (gint) (nuv->priv->h.d_aspect *
   763                                                  1000.0f), 1000, NULL);
   764 
   765         nuv->priv->src_video_pad =
   766             gst_nuv_demux_create_pad(nuv, video_caps, &video_src_template,
   767                                      "video_src");
   768         gst_caps_unref(video_caps);
   769     }
   770 
   771     if (nuv->priv->h.i_audio_blocks != 0) {
   772         GstCaps *audio_caps = NULL;
   773 
   774         audio_caps = gst_caps_new_simple("audio/mpeg",
   775                                          "rate", G_TYPE_INT, nuv->priv->eh.i_audio_sample_rate,
   776                                          "format", GST_TYPE_FOURCC, nuv->priv->eh.i_audio_fcc,
   777                                          "channels", G_TYPE_INT, nuv->priv->eh.i_audio_channels,
   778                                          "layer", G_TYPE_INT, 3, // fixme: magic number
   779                                          "mpegversion", G_TYPE_INT, nuv->priv->eh.i_version,
   780                                          NULL);
   781 
   782         nuv->priv->src_audio_pad =
   783             gst_nuv_demux_create_pad(nuv, audio_caps, &audio_src_template,
   784                                      "audio_src");
   785         gst_caps_unref(audio_caps);
   786     }
   787 
   788     gst_element_no_more_pads(GST_ELEMENT(nuv));
   789 }
   790 
   791 static          gboolean
   792 gst_nuv_demux_validate_header(nuv_frame_header * h)
   793 {
   794     gboolean        valid = FALSE;
   795     // g_usleep (1 * G_USEC_PER_SEC );
   796     switch (h->i_type) {
   797         /*
   798          * case 'V': if (h->i_compression == 0 || h->i_compression == 1 ||
   799          * h->i_compression == 2 || h->i_compression == 'N' ||
   800          * h->i_compression == 'L') { valid = TRUE; } break; case 'A': if
   801          * (h->i_compression == 0 || h->i_compression == 1 ||
   802          * h->i_compression == 2 || h->i_compression == 3 ||
   803          * h->i_compression == 'F' || h->i_compression == 'S' ||
   804          * h->i_compression == 'N' || h->i_compression == 'L') { valid =
   805          * TRUE; } break; case 'S': if (h->i_compression == 'B' ||
   806          * h->i_compression == 'A' || h->i_compression == 'V' ||
   807          * h->i_compression == 'S') { valid = TRUE; } break; 
   808          */
   809     case 'A':
   810     case 'V':
   811     case 'S':
   812     case 'R':
   813     case 'D':
   814     case 'Q':
   815         valid = TRUE;
   816         break;
   817     default:
   818         valid = FALSE;
   819     }
   820 
   821     return valid;
   822 }
   823 
   824 static          GstFlowReturn
   825 gst_nuv_demux_read_head_frame(GstNuvDemux * nuv)
   826 {
   827     GstFlowReturn   ret = GST_FLOW_OK;
   828     gboolean        valid = FALSE;
   829 
   830     do {
   831         ret = gst_nuv_demux_frame_header_load(nuv, &nuv->priv->fh);
   832         if (ret != GST_FLOW_OK) {
   833             return ret;
   834         }
   835 
   836         if (gst_nuv_demux_validate_header(&nuv->priv->fh) == TRUE)
   837             valid = TRUE;
   838 
   839     }
   840     while (valid == FALSE);
   841 
   842     nuv->priv->state = GST_NUV_DEMUX_MOVI;
   843     return ret;
   844 }
   845 
   846 static          gboolean
   847 gst_nuv_combine_flow(GstNuvDemux * nuv)
   848 {
   849     GstFlowReturn   ret_video = nuv->priv->last_video_return;
   850     GstFlowReturn   ret_audio = nuv->priv->last_audio_return;
   851 
   852     if ((ret_video != GST_FLOW_OK) && (ret_audio != GST_FLOW_OK))
   853         return FALSE;
   854 
   855     if (GST_FLOW_IS_FATAL(ret_video))
   856         return FALSE;
   857 
   858     if (GST_FLOW_IS_FATAL(ret_audio))
   859         return FALSE;
   860 
   861     return TRUE;
   862 }
   863 
   864 static GstFlowReturn
   865 gst_nuv_demux_stream_data(GstNuvDemux * nuv)
   866 {
   867     GstFlowReturn   ret = GST_FLOW_OK;
   868     GstPad         *pad = NULL;
   869     guint64         timestamp;
   870     GstBuffer      *buf = NULL;
   871     nuv_frame_header h;
   872 
   873     h = nuv->priv->fh;
   874 
   875     if (h.i_type == 'R') {
   876         goto done;
   877     }
   878 
   879     if (h.i_length > 0) {
   880         ret = gst_nuv_demux_read_bytes(nuv, h.i_length, TRUE, &buf);
   881         if ((ret != GST_FLOW_OK) || (buf == NULL)) {
   882             goto done;
   883         }
   884 
   885         if ((h.i_timecode > 0) && (h.i_type == 'V')) {
   886             g_debug ("TS: %ld", h.i_timecode);
   887             timestamp = h.i_timecode * GST_MSECOND;
   888             GST_BUFFER_TIMESTAMP(buf) = timestamp;
   889         }
   890 
   891     } else {
   892         goto done;
   893     }
   894 
   895 
   896     switch (h.i_type) {
   897     case 'V':
   898         {
   899             pad = nuv->priv->src_video_pad;
   900 
   901             if (nuv->priv->new_video_segment) {
   902 
   903                 /*
   904                  * send new segment event 
   905                  */
   906                 gst_pad_push_event(nuv->priv->src_video_pad,
   907                                    gst_event_new_new_segment(TRUE, 1.0,
   908                                                              GST_FORMAT_TIME,
   909                                                              0,
   910                                                              GST_CLOCK_TIME_NONE,
   911                                                              0));
   912 
   913                 if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
   914                     nuv->priv->time_start = timestamp;
   915                 }
   916                 nuv->priv->new_video_segment = FALSE;
   917             }
   918 
   919             break;
   920         }
   921     case 'A':
   922         {
   923             pad = nuv->priv->src_audio_pad;
   924 
   925             if (nuv->priv->new_audio_segment) {
   926                 /*
   927                  * send new segment event 
   928                  */
   929                 gst_pad_push_event(nuv->priv->src_audio_pad,
   930                                    gst_event_new_new_segment(TRUE, 1.0,
   931                                                              GST_FORMAT_TIME,
   932                                                              0,
   933                                                              GST_CLOCK_TIME_NONE,
   934                                                              0));
   935 
   936                 if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
   937                     nuv->priv->time_start = timestamp;
   938                 }
   939                 nuv->priv->new_audio_segment = FALSE;
   940             }
   941 
   942             break;
   943         }
   944     case 'S':
   945         {
   946             switch (h.i_compression) {
   947             case 'V':
   948                 GST_DEBUG_OBJECT(nuv, "sending new video segment: %d",
   949                                  h.i_timecode);
   950                 gst_pad_push_event(nuv->priv->src_video_pad,
   951                                    gst_event_new_new_segment(TRUE, 1.0,
   952                                                              GST_FORMAT_TIME,
   953                                                              h.i_timecode *
   954                                                              GST_MSECOND,
   955                                                              GST_CLOCK_TIME_NONE,
   956                                                              0));
   957                 break;
   958             case 'A':
   959                 GST_DEBUG_OBJECT(nuv, "sending new audio segment: %d",
   960                                  h.i_timecode);
   961                 gst_pad_push_event(nuv->priv->src_audio_pad,
   962                                    gst_event_new_new_segment(TRUE, 1.0,
   963                                                              GST_FORMAT_TIME,
   964                                                              0,
   965                                                              GST_CLOCK_TIME_NONE,
   966                                                              0));
   967                 break;
   968             default:
   969                 break;
   970             }
   971             goto done;
   972         }
   973     default:
   974         break;
   975     }
   976 
   977     if ((buf != NULL) && (pad != NULL)) {
   978         /*
   979          * pushing the buffer 
   980          */
   981         gst_buffer_set_caps(buf, GST_PAD_CAPS(pad));
   982         ret = gst_pad_push(pad, buf);
   983         buf = NULL;
   984 
   985         if (ret != GST_FLOW_OK) {
   986             GST_WARNING_OBJECT(nuv, "error: %d pushing on srcpad %s", ret,
   987                                gst_pad_get_name(pad));
   988 
   989             if (pad == nuv->priv->src_video_pad) {
   990                 nuv->priv->last_video_return = ret;
   991             } else if (pad == nuv->priv->src_audio_pad) {
   992                 nuv->priv->last_audio_return = ret;
   993             }
   994 
   995             /*
   996              * verify anothers flow if is necessary stop task 
   997              */
   998             if (gst_nuv_combine_flow(nuv) != FALSE) {
   999                 ret = GST_FLOW_OK;
  1000             } else {
  1001                 GST_WARNING_OBJECT(nuv, "error: on push");
  1002             }
  1003 
  1004         }
  1005     }
  1006 
  1007   done:
  1008     if (buf != NULL) {
  1009         gst_buffer_unref(buf);
  1010         buf = NULL;
  1011     }
  1012     if (ret == GST_FLOW_OK) {
  1013         nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
  1014         memset(&nuv->priv->fh, 0, sizeof(nuv->priv->fh));
  1015     }
  1016     return ret;
  1017 }
  1018 
  1019 static          GstFlowReturn
  1020 gst_nuv_demux_stream_mpeg_data(GstNuvDemux * nuv)
  1021 {
  1022     GstFlowReturn   ret = GST_FLOW_OK;
  1023 
  1024     /*
  1025      * ffmpeg extra data 
  1026      */
  1027     if (nuv->priv->new_file) {
  1028         GstBuffer      *buf;
  1029         ret =
  1030             gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE,
  1031                                      &buf);
  1032         gst_buffer_unref(buf);
  1033     } else {
  1034         ret =
  1035             gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE,
  1036                                      &nuv->priv->mpeg_buffer);
  1037     }
  1038 
  1039     if ((ret != GST_FLOW_OK) || (nuv->priv->mpeg_buffer == NULL)) {
  1040         return ret;
  1041     }
  1042 
  1043     GST_BUFFER_SIZE(nuv->priv->mpeg_buffer) = nuv->priv->mpeg_data_size;
  1044     nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
  1045     return ret;
  1046 }
  1047 
  1048 static          GstFlowReturn
  1049 gst_nuv_demux_stream_extra_data(GstNuvDemux * nuv)
  1050 {
  1051     GstFlowReturn   ret = GST_FLOW_OK;
  1052 
  1053     /*
  1054      * Load 'D' 
  1055      */
  1056     nuv_frame_header h;
  1057 
  1058     if (nuv->priv->new_file)
  1059         ret = gst_nuv_demux_frame_header_load(nuv, NULL);
  1060     else
  1061         ret = gst_nuv_demux_frame_header_load(nuv, &h);
  1062 
  1063     if (ret != GST_FLOW_OK)
  1064         return ret;
  1065 
  1066     if (h.i_type != 'D') {
  1067         GST_WARNING_OBJECT(nuv, "Unsuported rtjpeg");
  1068         return GST_FLOW_NOT_SUPPORTED;
  1069     }
  1070 
  1071     if (h.i_length > 0) {
  1072         if (h.i_compression == 'F') {
  1073             nuv->priv->state = GST_NUV_DEMUX_MPEG_DATA;
  1074         } else {
  1075             GST_WARNING_OBJECT(nuv,
  1076                                "only file with extended chunk are supported");
  1077             return GST_FLOW_NOT_SUPPORTED;
  1078         }
  1079     } else {
  1080         nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
  1081     }
  1082 
  1083     return ret;
  1084 }
  1085 
  1086 static          GstFlowReturn
  1087 gst_nuv_demux_stream_extend_header_data(GstNuvDemux * nuv)
  1088 {
  1089     GstFlowReturn   ret = GST_FLOW_OK;
  1090 
  1091     if (nuv->priv->new_file)
  1092         ret = gst_nuv_demux_extended_header_load(nuv, NULL);
  1093     else {
  1094         ret = gst_nuv_demux_extended_header_load(nuv, &nuv->priv->eh);
  1095         if (ret != GST_FLOW_OK)
  1096             return ret;
  1097         gst_nuv_demux_create_pads(nuv);
  1098     }
  1099 
  1100     nuv->priv->state = GST_NUV_DEMUX_INDEX_CREATE;
  1101     return ret;
  1102 }
  1103 
  1104 static          GstFlowReturn
  1105 gst_nuv_demux_stream_extend_header(GstNuvDemux * nuv)
  1106 {
  1107     GstBuffer      *buf = NULL;
  1108     GstFlowReturn   res = GST_FLOW_OK;
  1109 
  1110     res = gst_nuv_demux_read_bytes(nuv, 1, FALSE, &buf);
  1111     if ((res != GST_FLOW_OK) || (buf == NULL)) {
  1112         if (buf != NULL) {
  1113             gst_buffer_unref(buf);
  1114         }
  1115         return res;
  1116     }
  1117 
  1118     if (buf->data[0] == 'X') {
  1119         gst_buffer_unref(buf);
  1120         buf = NULL;
  1121         nuv_frame_header h;
  1122 
  1123         res = gst_nuv_demux_frame_header_load(nuv, &h);
  1124         if (res != GST_FLOW_OK)
  1125             return res;
  1126 
  1127         if (h.i_length != 512) {
  1128             return GST_FLOW_ERROR;
  1129         }
  1130         nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
  1131     } else {
  1132         nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
  1133         g_object_unref(buf);
  1134         GST_ELEMENT_WARNING(nuv, STREAM, FAILED,
  1135                             (_("incomplete NUV support")),
  1136                             ("incomplete NUV support"));
  1137         return GST_FLOW_ERROR;
  1138     }
  1139     return res;
  1140 }
  1141 
  1142 static void
  1143 gst_nuv_demux_create_seek_index(GstNuvDemux * nuv)
  1144 {
  1145     GstMessage     *msg;
  1146     nuv_frame_header h;
  1147 
  1148     while (gst_nuv_demux_frame_header_load(nuv, &h) == GST_FLOW_OK) {
  1149         if ((h.i_type == 'V') && (h.i_keyframe == 0)) {
  1150             frame_index_data *f = g_new0(frame_index_data, 1);
  1151 
  1152             f->offset = nuv->priv->offset - 12;
  1153             f->timecode = h.i_timecode * GST_MSECOND;
  1154 
  1155             nuv->priv->index = g_slist_append(nuv->priv->index, f);
  1156         }
  1157         if (h.i_type != 'R') {
  1158             nuv->priv->offset += h.i_length;
  1159             if (h.i_type == 'A' || h.i_type == 'V')
  1160                 nuv->priv->duration_time = h.i_timecode * GST_MSECOND;
  1161         }
  1162     }
  1163     GST_DEBUG_OBJECT(nuv,
  1164                      "CREATING INDEX: DONE : DURATION Bytes/Sec: %"
  1165                      G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
  1166                      nuv->priv->offset, nuv->priv->duration_time);
  1167 
  1168     nuv->priv->duration_bytes = nuv->priv->offset;
  1169     nuv->priv->offset = nuv->priv->header_lengh;
  1170 
  1171     msg =
  1172         gst_message_new_duration(GST_OBJECT(nuv), GST_FORMAT_TIME,
  1173                                  nuv->priv->duration_time);
  1174     gst_element_post_message(GST_ELEMENT(nuv), msg);
  1175 }
  1176 
  1177 static          GstFlowReturn
  1178 gst_nuv_demux_play(GstPad * pad)
  1179 {
  1180     GstFlowReturn   res = GST_FLOW_OK;
  1181     GstNuvDemux    *nuv = GST_NUV_DEMUX(GST_PAD_PARENT(pad));
  1182 
  1183     switch (nuv->priv->state) {
  1184     case GST_NUV_DEMUX_START:
  1185         res = gst_nuv_demux_stream_file_header(nuv);
  1186         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1187             goto pause;
  1188         }
  1189         break;
  1190 
  1191     case GST_NUV_DEMUX_HEADER_DATA:
  1192         res = gst_nuv_demux_stream_header_data(nuv);
  1193         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1194             goto pause;
  1195         }
  1196         break;
  1197 
  1198     case GST_NUV_DEMUX_EXTRA_DATA:
  1199         res = gst_nuv_demux_stream_extra_data(nuv);
  1200         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1201             goto pause;
  1202         }
  1203         break;
  1204 
  1205     case GST_NUV_DEMUX_MPEG_DATA:
  1206         res = gst_nuv_demux_stream_mpeg_data(nuv);
  1207         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1208             goto pause;
  1209         }
  1210         break;
  1211 
  1212     case GST_NUV_DEMUX_EXTEND_HEADER:
  1213         res = gst_nuv_demux_stream_extend_header(nuv);
  1214         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1215             goto pause;
  1216         }
  1217         break;
  1218 
  1219     case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
  1220         res = gst_nuv_demux_stream_extend_header_data(nuv);
  1221         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1222             goto pause;
  1223         }
  1224         // store file header size
  1225         nuv->priv->header_lengh = nuv->priv->offset;
  1226         break;
  1227 
  1228     case GST_NUV_DEMUX_INDEX_CREATE:
  1229         if ((nuv->priv->mode == NUV_PULL_MODE) && (!nuv->priv->new_file)) {
  1230             gst_nuv_demux_create_seek_index(nuv);
  1231         }
  1232 
  1233     case GST_NUV_DEMUX_FRAME_HEADER:
  1234         res = gst_nuv_demux_read_head_frame(nuv);
  1235         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1236             goto pause;
  1237         }
  1238         break;
  1239 
  1240     case GST_NUV_DEMUX_MOVI:
  1241         res = gst_nuv_demux_stream_data(nuv);
  1242         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1243             goto pause;
  1244         }
  1245         break;
  1246 
  1247     case GST_NUV_DEMUX_INVALID_DATA:
  1248         goto pause;
  1249         break;
  1250     default:
  1251         g_assert_not_reached();
  1252     }
  1253 
  1254     return GST_FLOW_OK;
  1255 
  1256   pause:
  1257     GST_LOG_OBJECT(nuv, "pausing task, reason %s", gst_flow_get_name(res));
  1258     gst_pad_pause_task(nuv->priv->sinkpad);
  1259 
  1260     if (res == GST_FLOW_ERROR_EOS) {
  1261         gst_nuv_demux_send_eos(nuv);
  1262         nuv->priv->eos = TRUE;
  1263         res = GST_FLOW_OK;
  1264     }
  1265 
  1266     if (GST_FLOW_IS_FATAL(res)) {
  1267         GST_ELEMENT_ERROR(nuv, STREAM, FAILED,
  1268                           (_("Internal data stream error.")),
  1269                           ("streaming stopped, reason %s",
  1270                            gst_flow_get_name(res)));
  1271 
  1272         gst_nuv_demux_send_eos(nuv);
  1273     }
  1274     return res;
  1275 }
  1276 
  1277 static void
  1278 gst_nuv_demux_send_eos(GstNuvDemux * nuv)
  1279 {
  1280     gst_element_post_message(GST_ELEMENT(nuv),
  1281                              gst_message_new_segment_done(GST_OBJECT(nuv),
  1282                                                           GST_FORMAT_TIME,
  1283                                                           -1));
  1284 
  1285     if (nuv->priv->src_video_pad)
  1286         gst_pad_push_event(nuv->priv->src_video_pad, gst_event_new_eos());
  1287     if (nuv->priv->src_audio_pad)
  1288         gst_pad_push_event(nuv->priv->src_audio_pad, gst_event_new_eos());
  1289 }
  1290 
  1291 static          GstFlowReturn
  1292 gst_nuv_demux_read_bytes(GstNuvDemux * nuv, guint64 size, gboolean move,
  1293                          GstBuffer ** buffer)
  1294 {
  1295     GstFlowReturn   ret = GST_FLOW_OK;
  1296 
  1297     if (size == 0) {
  1298         return ret;
  1299     }
  1300 
  1301     if (nuv->priv->mode == NUV_PULL_MODE) {
  1302         ret =
  1303             gst_pad_pull_range(nuv->priv->sinkpad, nuv->priv->offset, size,
  1304                                buffer);
  1305         if (ret == GST_FLOW_OK) {
  1306             if (move) {
  1307                 nuv->priv->offset += size;
  1308             }
  1309             /*
  1310              * got eos 
  1311              */
  1312         } else if (ret == GST_FLOW_UNEXPECTED) {
  1313             return GST_FLOW_ERROR_EOS;
  1314         }
  1315     } else {
  1316         if (gst_adapter_available(nuv->priv->adapter) < size) {
  1317             nuv->priv->more_data = TRUE;
  1318             return GST_FLOW_ERROR_NO_DATA;
  1319         }
  1320         if (move) {
  1321             *buffer = gst_adapter_take_buffer(nuv->priv->adapter, size);
  1322         } else {
  1323             guint8         *data = NULL;
  1324             data = (guint8 *) gst_adapter_peek(nuv->priv->adapter, size);
  1325             *buffer = gst_buffer_new();
  1326             gst_buffer_set_data(*buffer, data, size);
  1327         }
  1328     }
  1329     return ret;
  1330 }
  1331 
  1332 static          GstFlowReturn
  1333 gst_nuv_demux_move_bytes(GstNuvDemux * nuv, guint64 size)
  1334 {
  1335     GstFlowReturn   ret = GST_FLOW_OK;
  1336 
  1337     if (size == 0) {
  1338         return ret;
  1339     }
  1340 
  1341     if (nuv->priv->mode == NUV_PULL_MODE) {
  1342         nuv->priv->offset += size;
  1343     } else {
  1344         if (gst_adapter_available(nuv->priv->adapter) < size) {
  1345             nuv->priv->more_data = TRUE;
  1346             return GST_FLOW_ERROR_NO_DATA;
  1347         }
  1348         gst_adapter_flush(nuv->priv->adapter, size);
  1349     }
  1350     return ret;
  1351 }
  1352 
  1353 static          gboolean
  1354 gst_nuv_demux_sink_activate(GstPad * sinkpad)
  1355 {
  1356     gboolean        res = TRUE;
  1357     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
  1358 
  1359     if (gst_pad_check_pull_range(sinkpad)) {
  1360         gst_adapter_clear(nuv->priv->adapter);
  1361         res = gst_pad_activate_pull(sinkpad, TRUE);
  1362     } else {
  1363         gst_adapter_clear(nuv->priv->adapter);
  1364         res = gst_pad_activate_push(sinkpad, TRUE);
  1365     }
  1366 
  1367     g_object_unref(nuv);
  1368     return res;
  1369 }
  1370 
  1371 static          gboolean
  1372 gst_nuv_demux_sink_activate_pull(GstPad * sinkpad, gboolean active)
  1373 {
  1374     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
  1375 
  1376     if (active) {
  1377         GST_DEBUG_OBJECT(nuv, "activating pull function");
  1378         nuv->priv->mode = NUV_PULL_MODE;
  1379         gst_adapter_clear(nuv->priv->adapter);
  1380 
  1381         gst_pad_start_task(sinkpad, (GstTaskFunction) gst_nuv_demux_loop,
  1382                            sinkpad);
  1383     } else {
  1384         GST_DEBUG_OBJECT(nuv, "deactivating pull function");
  1385         gst_pad_stop_task(sinkpad);
  1386     }
  1387     gst_object_unref(nuv);
  1388 
  1389     return TRUE;
  1390 }
  1391 
  1392 static          gboolean
  1393 gst_nuv_demux_sink_activate_push(GstPad * pad, gboolean active)
  1394 {
  1395     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1396 
  1397     if (active) {
  1398         nuv->priv->mode = NUV_PUSH_MODE;
  1399         gst_adapter_clear(nuv->priv->adapter);
  1400 
  1401         GST_DEBUG_OBJECT(nuv, "activating push/chain function");
  1402     } else {
  1403         GST_DEBUG_OBJECT(nuv, "deactivating push/chain function");
  1404     }
  1405 
  1406     gst_object_unref(nuv);
  1407 
  1408     return TRUE;
  1409 }
  1410 
  1411 static frame_index_data *
  1412 gst_nuv_demux_do_seek_index(GstNuvDemux * nuv, gint64 seek_pos,
  1413                             gint64 segment_stop, GstFormat format)
  1414 {
  1415     GSList         *l;
  1416     frame_index_data *ret = NULL;
  1417 
  1418     if (nuv->priv->index == NULL) {
  1419         return NULL;
  1420     }
  1421 
  1422     /*
  1423      * find keyframe closest to the requested position 
  1424      */
  1425     for (l = nuv->priv->index; l != NULL; l = l->next) {
  1426         frame_index_data *f = (frame_index_data *) l->data;
  1427         gint64          pos = 0;
  1428 
  1429         if (format == GST_FORMAT_BYTES) {
  1430             pos = f->offset;
  1431         } else if (format == GST_FORMAT_TIME) {
  1432             pos = f->timecode;
  1433         } else {
  1434             return NULL;
  1435         }
  1436 
  1437         if (pos >= seek_pos) {
  1438             ret = f;
  1439             break;
  1440         }
  1441 
  1442         if ((segment_stop != -1) && (segment_stop != GST_CLOCK_TIME_NONE)
  1443             && (pos > segment_stop)) {
  1444             break;
  1445         }
  1446     }
  1447 
  1448     return ret;
  1449 }
  1450 
  1451 static          gboolean
  1452 gst_nuv_demux_do_seek(GstNuvDemux * nuv, GstEvent * event)
  1453 {
  1454     gdouble         rate;
  1455     GstFormat       format;
  1456     GstSeekFlags    flags;
  1457     GstSeekType     cur_type;
  1458     gint64          cur;
  1459     GstSeekType     stop_type;
  1460     gint64          stop;
  1461     gboolean        flush;
  1462     frame_index_data *entry;
  1463     gint64          segment_start;
  1464     gint64          segment_stop;
  1465     GstEvent       *newsegment_event;
  1466 
  1467     if (nuv->priv->eos) {
  1468         return FALSE;
  1469     }
  1470 
  1471     if (nuv->priv->mode == NUV_PUSH_MODE) {
  1472         return FALSE;
  1473     }
  1474 
  1475 
  1476     gst_event_parse_seek(event, &rate, &format, &flags,
  1477                          &cur_type, &cur, &stop_type, &stop);
  1478 
  1479 
  1480 
  1481     /*
  1482      * if (format == GST_FORMAT_TIME) { GST_DEBUG_OBJECT (nuv, "Can only
  1483      * seek on BYTES"); return FALSE; } 
  1484      */
  1485 
  1486     if (rate <= 0.0) {
  1487         GST_DEBUG_OBJECT(nuv, "Can only seek with positive rate");
  1488         return FALSE;
  1489     }
  1490 
  1491     if (cur_type == GST_SEEK_TYPE_SET) {
  1492         GST_OBJECT_LOCK(nuv);
  1493         if (gst_nuv_demux_do_seek_index(nuv, cur, -1, format) == NULL) {
  1494             GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
  1495             GST_OBJECT_UNLOCK(nuv);
  1496             return FALSE;
  1497         }
  1498         GST_OBJECT_UNLOCK(nuv);
  1499     }
  1500 
  1501     flush = !!(flags & GST_SEEK_FLAG_FLUSH);
  1502 
  1503     if (flush) {
  1504         gst_pad_push_event(nuv->priv->sinkpad,
  1505                            gst_event_new_flush_start());
  1506         if (nuv->priv->src_video_pad != NULL) {
  1507             gst_pad_push_event(nuv->priv->src_video_pad,
  1508                                gst_event_new_flush_start());
  1509         }
  1510 
  1511         if (nuv->priv->src_audio_pad != NULL) {
  1512             gst_pad_push_event(nuv->priv->src_audio_pad,
  1513                                gst_event_new_flush_start());
  1514         }
  1515     } else {
  1516         gst_pad_pause_task(nuv->priv->sinkpad);
  1517     }
  1518 
  1519     GST_PAD_STREAM_LOCK(nuv->priv->sinkpad);
  1520     GST_OBJECT_LOCK(nuv);
  1521 
  1522 
  1523     if (cur == GST_CLOCK_TIME_NONE)
  1524         cur = 0;
  1525     if (stop == GST_CLOCK_TIME_NONE)
  1526         stop = nuv->priv->duration_time;
  1527 
  1528     if (cur_type == GST_SEEK_TYPE_SET)
  1529         segment_start = cur;
  1530     else if (cur_type == GST_SEEK_TYPE_CUR)
  1531         segment_start = nuv->priv->segment_start + cur;
  1532     else
  1533         segment_start = nuv->priv->segment_start;
  1534 
  1535     if (stop_type == GST_SEEK_TYPE_SET)
  1536         segment_stop = stop;
  1537     else if (stop_type == GST_SEEK_TYPE_CUR)
  1538         segment_stop = nuv->priv->segment_stop + stop;
  1539     else
  1540         segment_stop = nuv->priv->segment_stop;
  1541 
  1542     segment_start = CLAMP(segment_start, 0, nuv->priv->duration_time);
  1543     segment_stop = CLAMP(segment_stop, 0, nuv->priv->duration_time);
  1544 
  1545     entry = gst_nuv_demux_do_seek_index(nuv, segment_start,
  1546                                         segment_stop, format);
  1547 
  1548     if (entry == NULL) {
  1549         GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
  1550         goto seek_error;
  1551     }
  1552 
  1553     segment_start = entry->timecode;
  1554 
  1555     nuv->priv->segment_start = segment_start;
  1556     nuv->priv->segment_stop = segment_stop;
  1557 
  1558     GST_OBJECT_UNLOCK(nuv);
  1559 
  1560     if (!nuv->priv->eos) {
  1561         GstMessage     *msg;
  1562         msg =
  1563             gst_message_new_segment_start(GST_OBJECT(nuv), GST_FORMAT_TIME,
  1564                                           nuv->priv->segment_start);
  1565 
  1566         gst_element_post_message(GST_ELEMENT(nuv), msg);
  1567     }
  1568 
  1569     GST_DEBUG_OBJECT(nuv,
  1570                      "NEW SEGMENT START %" G_GUINT64_FORMAT ", STOP %"
  1571                      G_GUINT64_FORMAT, segment_start, segment_stop);
  1572     newsegment_event =
  1573         gst_event_new_new_segment(FALSE, rate, GST_FORMAT_TIME,
  1574                                   segment_start, segment_stop,
  1575                                   segment_start);
  1576 
  1577 
  1578     if (flush) {
  1579         if (nuv->priv->src_video_pad != NULL) {
  1580             gst_pad_push_event(nuv->priv->src_video_pad,
  1581                                gst_event_new_flush_stop());
  1582         }
  1583 
  1584         if (nuv->priv->src_audio_pad != NULL) {
  1585             gst_pad_push_event(nuv->priv->src_audio_pad,
  1586                                gst_event_new_flush_stop());
  1587         }
  1588 
  1589         gst_pad_push_event(nuv->priv->sinkpad, gst_event_new_flush_stop());
  1590     }
  1591 
  1592 
  1593     if (nuv->priv->src_video_pad != NULL) {
  1594         gst_pad_push_event(nuv->priv->src_video_pad,
  1595                            gst_event_ref(newsegment_event));
  1596     }
  1597     if (nuv->priv->src_audio_pad != NULL) {
  1598         gst_pad_push_event(nuv->priv->src_audio_pad,
  1599                            gst_event_ref(newsegment_event));
  1600     }
  1601 
  1602     gst_event_unref(newsegment_event);
  1603 
  1604     nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
  1605     nuv->priv->offset = entry->offset;
  1606 
  1607     gst_pad_start_task(nuv->priv->sinkpad,
  1608                        (GstTaskFunction) gst_nuv_demux_loop,
  1609                        nuv->priv->sinkpad);
  1610 
  1611     GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
  1612     return TRUE;
  1613 
  1614   seek_error:
  1615     GST_DEBUG_OBJECT(nuv, "Got a seek error");
  1616     GST_OBJECT_UNLOCK(nuv);
  1617     GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
  1618     return FALSE;
  1619 
  1620 }
  1621 
  1622 static          gboolean
  1623 gst_nuv_demux_srcpad_event(GstPad * pad, GstEvent * event)
  1624 {
  1625     gboolean        res = FALSE;
  1626     GstNuvDemux    *nuv;
  1627 
  1628     nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1629 
  1630     switch (GST_EVENT_TYPE(event)) {
  1631     case GST_EVENT_SEEK:
  1632         res = gst_nuv_demux_do_seek(nuv, event);
  1633         break;
  1634     default:
  1635         res = FALSE;
  1636         break;
  1637     }
  1638 
  1639     gst_object_unref(nuv);
  1640     return res;
  1641 }
  1642 
  1643 static          gboolean
  1644 gst_nuv_demux_sink_event(GstPad * pad, GstEvent * event)
  1645 {
  1646     gboolean        res = FALSE;
  1647     GstNuvDemux    *nuv;
  1648 
  1649     nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1650 
  1651     switch (GST_EVENT_TYPE(event)) {
  1652         case GST_EVENT_NEWSEGMENT:
  1653             GST_PAD_STREAM_LOCK(pad);
  1654             gst_nuv_demux_reset(nuv);
  1655             GST_PAD_STREAM_UNLOCK(pad);
  1656 
  1657             //res = gst_pad_event_default(pad, event);
  1658             res = TRUE;
  1659             break;
  1660         default:
  1661             res = gst_pad_event_default(pad, event);
  1662             break;
  1663     }
  1664 
  1665     return res;
  1666 }
  1667 
  1668 static          GstFlowReturn
  1669 gst_nuv_demux_chain(GstPad * pad, GstBuffer * buf)
  1670 {
  1671     GstFlowReturn   ret = GST_FLOW_OK;
  1672     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1673 
  1674     if (nuv->priv->mode != NUV_PUSH_MODE)
  1675         return ret;
  1676 
  1677     gst_adapter_push(nuv->priv->adapter, buf);
  1678 
  1679     while ((ret == GST_FLOW_OK) && (nuv->priv->more_data == FALSE)) {
  1680         ret = gst_nuv_demux_play(pad);
  1681     }
  1682 
  1683     nuv->priv->more_data = FALSE;
  1684     gst_object_unref(nuv);
  1685 
  1686     return ret;
  1687 }
  1688 
  1689 static void
  1690 gst_nuv_demux_loop(GstPad * pad)
  1691 {
  1692     gst_nuv_demux_play(pad);
  1693 }
  1694 
  1695 static void
  1696 gst_nuv_demux_index_free(gpointer data, gpointer user_data)
  1697 {
  1698     g_free(data);
  1699 }
  1700 
  1701 static void
  1702 gst_nuv_demux_reset(GstNuvDemux * nuv)
  1703 {
  1704     nuv->priv->eos = FALSE;
  1705     nuv->priv->more_data = FALSE;
  1706     nuv->priv->state = GST_NUV_DEMUX_START;
  1707     nuv->priv->mode = NUV_PUSH_MODE;
  1708     nuv->priv->offset = 0;
  1709     nuv->priv->time_start = 0;
  1710     nuv->priv->time_qos = GST_CLOCK_TIME_NONE;
  1711     nuv->priv->duration_bytes = GST_CLOCK_TIME_NONE;
  1712     nuv->priv->duration_time = GST_CLOCK_TIME_NONE;
  1713     nuv->priv->last_video_return = GST_FLOW_OK;
  1714     nuv->priv->last_audio_return = GST_FLOW_OK;
  1715     nuv->priv->header_lengh = 0;
  1716     nuv->priv->segment_stop = GST_CLOCK_TIME_NONE;
  1717     nuv->priv->segment_start = GST_CLOCK_TIME_NONE;
  1718     nuv->priv->new_file = FALSE;
  1719 
  1720     // clear index list
  1721     g_slist_foreach(nuv->priv->index, gst_nuv_demux_index_free, NULL);
  1722     g_slist_free(nuv->priv->index);
  1723     nuv->priv->index = NULL;
  1724 
  1725     gst_adapter_clear(nuv->priv->adapter);
  1726 
  1727     if (nuv->priv->mpeg_buffer != NULL) {
  1728         gst_buffer_unref(nuv->priv->mpeg_buffer);
  1729         nuv->priv->mpeg_buffer = NULL;
  1730     }
  1731 }
  1732 
  1733 static void
  1734 gst_nuv_demux_destoy_src_pad(GstNuvDemux * nuv)
  1735 {
  1736     if (nuv->priv->src_video_pad) {
  1737         gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_video_pad);
  1738         nuv->priv->src_video_pad = NULL;
  1739     }
  1740 
  1741     if (nuv->priv->src_audio_pad) {
  1742         gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_audio_pad);
  1743         nuv->priv->src_audio_pad = NULL;
  1744     }
  1745 }
  1746 
  1747 static          GstStateChangeReturn
  1748 gst_nuv_demux_change_state(GstElement * element, GstStateChange transition)
  1749 {
  1750     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  1751 
  1752     switch (transition) {
  1753     case GST_STATE_CHANGE_NULL_TO_READY:
  1754         gst_nuv_demux_reset(GST_NUV_DEMUX(element));
  1755         gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
  1756         break;
  1757     default:
  1758         break;
  1759     }
  1760 
  1761     ret =
  1762         GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
  1763     if (ret == GST_STATE_CHANGE_FAILURE) {
  1764         goto done;
  1765     }
  1766 
  1767 
  1768     switch (transition) {
  1769     case GST_STATE_CHANGE_READY_TO_NULL:
  1770         gst_nuv_demux_reset(GST_NUV_DEMUX(element));
  1771         gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
  1772         break;
  1773     default:
  1774         break;
  1775     }
  1776   done:
  1777     return ret;
  1778 }
  1779 
  1780 #if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
  1781 GstBuffer      *
  1782 gst_adapter_take_buffer(GstAdapter * adapter, guint nbytes)
  1783 {
  1784     GstBuffer      *buffer;
  1785     GstBuffer      *cur;
  1786     guint8         *data;
  1787 
  1788     g_return_val_if_fail(GST_IS_ADAPTER(adapter), NULL);
  1789     g_return_val_if_fail(nbytes > 0, NULL);
  1790 
  1791     GST_LOG_OBJECT(adapter, "taking buffer of %u bytes", nbytes);
  1792 
  1793     /*
  1794      * we don't have enough data, return NULL. This is unlikely as one
  1795      * usually does an _available() first instead of peeking a random
  1796      * size. 
  1797      */
  1798     if (G_UNLIKELY(nbytes > adapter->size))
  1799         return NULL;
  1800 
  1801     /*
  1802      * our head buffer has enough data left, return it 
  1803      */
  1804     cur = adapter->buflist->data;
  1805     if (GST_BUFFER_SIZE(cur) >= nbytes + adapter->skip) {
  1806         GST_LOG_OBJECT(adapter,
  1807                        "providing buffer of %d bytes via sub-buffer",
  1808                        nbytes);
  1809         buffer = gst_buffer_create_sub(cur, adapter->skip, nbytes);
  1810 
  1811         gst_adapter_flush(adapter, nbytes);
  1812 
  1813         return buffer;
  1814     }
  1815 
  1816     data = gst_adapter_take(adapter, nbytes);
  1817     if (data == NULL)
  1818         return NULL;
  1819 
  1820     buffer = gst_buffer_new();
  1821     GST_BUFFER_DATA(buffer) = data;
  1822     GST_BUFFER_MALLOCDATA(buffer) = data;
  1823     GST_BUFFER_SIZE(buffer) = nbytes;
  1824 
  1825     return buffer;
  1826 }
  1827 #endif
  1828 
  1829 static void
  1830 gst_nuv_typefind(GstTypeFind * tf, gpointer unused)
  1831 {
  1832     guint8         *data = gst_type_find_peek(tf, 0, 11);
  1833 
  1834     if (data) {
  1835         if (memcmp(data, "MythTVVideo", 11) == 0
  1836             || memcmp(data, "NuppelVideo", 11) == 0) {
  1837             gst_type_find_suggest(tf, GST_TYPE_FIND_MAXIMUM,
  1838                                   gst_caps_new_simple("video/x-nuv",
  1839                                                       NULL));
  1840         }
  1841     }
  1842 }
  1843 
  1844 static          gboolean
  1845 plugin_init(GstPlugin * plugin)
  1846 {
  1847     static gchar   *exts[] = { "nuv", NULL };
  1848 #ifdef ENABLE_NLS
  1849     setlocale(LC_ALL, "");
  1850     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
  1851 #endif                          /* ENABLE_NLS */
  1852 
  1853     if (!gst_element_register(plugin, "nuvdemux", GST_RANK_SECONDARY,
  1854                               GST_TYPE_NUV_DEMUX)) {
  1855         return FALSE;
  1856     }
  1857 
  1858     if (!gst_type_find_register(plugin, "video/x-nuv", GST_RANK_SECONDARY,
  1859                                 gst_nuv_typefind,
  1860                                 exts,
  1861                                 gst_caps_new_simple("video/x-nuv", NULL),
  1862                                 NULL, NULL)) {
  1863         GST_WARNING("can't register typefind");
  1864         return FALSE;
  1865     }
  1866 
  1867     return TRUE;
  1868 }
  1869 
  1870 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
  1871                   GST_VERSION_MINOR,
  1872                   "nuvdemux",
  1873                   "Demuxes and muxes audio and video",
  1874                   plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
  1875                   GST_PACKAGE_ORIGIN)