gst-gmyth/nuvdemux/gstnuvdemux.c
author melunko
Mon Oct 08 19:35:09 2007 +0100 (2007-10-08)
branchtrunk
changeset 860 bb5592a9ac48
parent 754 cb885ee44618
child 880 22df7edb6e37
permissions -rw-r--r--
[svn r866] Fixed gst-gmyth Makefile to get source from gstreamer cvs
     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)) {
   886             h.i_timecode = 0;
   887             // goto done;
   888         }
   889 
   890         timestamp = h.i_timecode * GST_MSECOND;
   891         GST_BUFFER_TIMESTAMP(buf) = timestamp;
   892     } else {
   893         goto done;
   894     }
   895 
   896 
   897     switch (h.i_type) {
   898     case 'V':
   899         {
   900             pad = nuv->priv->src_video_pad;
   901 
   902             if (nuv->priv->new_video_segment) {
   903 
   904                 /*
   905                  * send new segment event 
   906                  */
   907                 gst_pad_push_event(nuv->priv->src_video_pad,
   908                                    gst_event_new_new_segment(TRUE, 1.0,
   909                                                              GST_FORMAT_TIME,
   910                                                              0,
   911                                                              GST_CLOCK_TIME_NONE,
   912                                                              0));
   913 
   914                 if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
   915                     nuv->priv->time_start = timestamp;
   916                 }
   917                 nuv->priv->new_video_segment = FALSE;
   918             }
   919 
   920             break;
   921         }
   922     case 'A':
   923         {
   924             pad = nuv->priv->src_audio_pad;
   925 
   926             if (nuv->priv->new_audio_segment) {
   927                 /*
   928                  * send new segment event 
   929                  */
   930                 gst_pad_push_event(nuv->priv->src_audio_pad,
   931                                    gst_event_new_new_segment(TRUE, 1.0,
   932                                                              GST_FORMAT_TIME,
   933                                                              0,
   934                                                              GST_CLOCK_TIME_NONE,
   935                                                              0));
   936 
   937                 if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
   938                     nuv->priv->time_start = timestamp;
   939                 }
   940                 nuv->priv->new_audio_segment = FALSE;
   941             }
   942 
   943             break;
   944         }
   945     case 'S':
   946         {
   947             switch (h.i_compression) {
   948             case 'V':
   949                 GST_DEBUG_OBJECT(nuv, "sending new video segment: %d",
   950                                  h.i_timecode);
   951                 gst_pad_push_event(nuv->priv->src_video_pad,
   952                                    gst_event_new_new_segment(TRUE, 1.0,
   953                                                              GST_FORMAT_TIME,
   954                                                              h.i_timecode *
   955                                                              GST_MSECOND,
   956                                                              GST_CLOCK_TIME_NONE,
   957                                                              0));
   958                 break;
   959             case 'A':
   960                 GST_DEBUG_OBJECT(nuv, "sending new audio segment: %d",
   961                                  h.i_timecode);
   962                 gst_pad_push_event(nuv->priv->src_audio_pad,
   963                                    gst_event_new_new_segment(TRUE, 1.0,
   964                                                              GST_FORMAT_TIME,
   965                                                              0,
   966                                                              GST_CLOCK_TIME_NONE,
   967                                                              0));
   968                 break;
   969             default:
   970                 break;
   971             }
   972             goto done;
   973         }
   974     default:
   975         break;
   976     }
   977 
   978     if ((buf != NULL) && (pad != NULL)) {
   979         /*
   980          * pushing the buffer 
   981          */
   982         gst_buffer_set_caps(buf, GST_PAD_CAPS(pad));
   983         ret = gst_pad_push(pad, buf);
   984         buf = NULL;
   985 
   986         if (ret != GST_FLOW_OK) {
   987             GST_WARNING_OBJECT(nuv, "error: %d pushing on srcpad %s", ret,
   988                                gst_pad_get_name(pad));
   989 
   990             if (pad == nuv->priv->src_video_pad) {
   991                 nuv->priv->last_video_return = ret;
   992             } else if (pad == nuv->priv->src_audio_pad) {
   993                 nuv->priv->last_audio_return = ret;
   994             }
   995 
   996             /*
   997              * verify anothers flow if is necessary stop task 
   998              */
   999             if (gst_nuv_combine_flow(nuv) != FALSE) {
  1000                 ret = GST_FLOW_OK;
  1001             } else {
  1002                 GST_WARNING_OBJECT(nuv, "error: on push");
  1003             }
  1004 
  1005         }
  1006     }
  1007 
  1008   done:
  1009     if (buf != NULL) {
  1010         gst_buffer_unref(buf);
  1011         buf = NULL;
  1012     }
  1013     if (ret == GST_FLOW_OK) {
  1014         nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
  1015         memset(&nuv->priv->fh, 0, sizeof(nuv->priv->fh));
  1016     }
  1017     return ret;
  1018 }
  1019 
  1020 static          GstFlowReturn
  1021 gst_nuv_demux_stream_mpeg_data(GstNuvDemux * nuv)
  1022 {
  1023     GstFlowReturn   ret = GST_FLOW_OK;
  1024 
  1025     /*
  1026      * ffmpeg extra data 
  1027      */
  1028     if (nuv->priv->new_file) {
  1029         GstBuffer      *buf;
  1030         ret =
  1031             gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE,
  1032                                      &buf);
  1033         gst_buffer_unref(buf);
  1034     } else {
  1035         ret =
  1036             gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE,
  1037                                      &nuv->priv->mpeg_buffer);
  1038     }
  1039 
  1040     if ((ret != GST_FLOW_OK) || (nuv->priv->mpeg_buffer == NULL)) {
  1041         return ret;
  1042     }
  1043 
  1044     GST_BUFFER_SIZE(nuv->priv->mpeg_buffer) = nuv->priv->mpeg_data_size;
  1045     nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
  1046     return ret;
  1047 }
  1048 
  1049 static          GstFlowReturn
  1050 gst_nuv_demux_stream_extra_data(GstNuvDemux * nuv)
  1051 {
  1052     GstFlowReturn   ret = GST_FLOW_OK;
  1053 
  1054     /*
  1055      * Load 'D' 
  1056      */
  1057     nuv_frame_header h;
  1058 
  1059     if (nuv->priv->new_file)
  1060         ret = gst_nuv_demux_frame_header_load(nuv, NULL);
  1061     else
  1062         ret = gst_nuv_demux_frame_header_load(nuv, &h);
  1063 
  1064     if (ret != GST_FLOW_OK)
  1065         return ret;
  1066 
  1067     if (h.i_type != 'D') {
  1068         GST_WARNING_OBJECT(nuv, "Unsuported rtjpeg");
  1069         return GST_FLOW_NOT_SUPPORTED;
  1070     }
  1071 
  1072     if (h.i_length > 0) {
  1073         if (h.i_compression == 'F') {
  1074             nuv->priv->state = GST_NUV_DEMUX_MPEG_DATA;
  1075         } else {
  1076             GST_WARNING_OBJECT(nuv,
  1077                                "only file with extended chunk are supported");
  1078             return GST_FLOW_NOT_SUPPORTED;
  1079         }
  1080     } else {
  1081         nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
  1082     }
  1083 
  1084     return ret;
  1085 }
  1086 
  1087 static          GstFlowReturn
  1088 gst_nuv_demux_stream_extend_header_data(GstNuvDemux * nuv)
  1089 {
  1090     GstFlowReturn   ret = GST_FLOW_OK;
  1091 
  1092     if (nuv->priv->new_file)
  1093         ret = gst_nuv_demux_extended_header_load(nuv, NULL);
  1094     else {
  1095         ret = gst_nuv_demux_extended_header_load(nuv, &nuv->priv->eh);
  1096         if (ret != GST_FLOW_OK)
  1097             return ret;
  1098         gst_nuv_demux_create_pads(nuv);
  1099     }
  1100 
  1101     nuv->priv->state = GST_NUV_DEMUX_INDEX_CREATE;
  1102     return ret;
  1103 }
  1104 
  1105 static          GstFlowReturn
  1106 gst_nuv_demux_stream_extend_header(GstNuvDemux * nuv)
  1107 {
  1108     GstBuffer      *buf = NULL;
  1109     GstFlowReturn   res = GST_FLOW_OK;
  1110 
  1111     res = gst_nuv_demux_read_bytes(nuv, 1, FALSE, &buf);
  1112     if ((res != GST_FLOW_OK) || (buf == NULL)) {
  1113         if (buf != NULL) {
  1114             gst_buffer_unref(buf);
  1115         }
  1116         return res;
  1117     }
  1118 
  1119     if (buf->data[0] == 'X') {
  1120         gst_buffer_unref(buf);
  1121         buf = NULL;
  1122         nuv_frame_header h;
  1123 
  1124         res = gst_nuv_demux_frame_header_load(nuv, &h);
  1125         if (res != GST_FLOW_OK)
  1126             return res;
  1127 
  1128         if (h.i_length != 512) {
  1129             return GST_FLOW_ERROR;
  1130         }
  1131         nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
  1132     } else {
  1133         nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
  1134         g_object_unref(buf);
  1135         GST_ELEMENT_WARNING(nuv, STREAM, FAILED,
  1136                             (_("incomplete NUV support")),
  1137                             ("incomplete NUV support"));
  1138         return GST_FLOW_ERROR;
  1139     }
  1140     return res;
  1141 }
  1142 
  1143 static void
  1144 gst_nuv_demux_create_seek_index(GstNuvDemux * nuv)
  1145 {
  1146     GstMessage     *msg;
  1147     nuv_frame_header h;
  1148 
  1149     while (gst_nuv_demux_frame_header_load(nuv, &h) == GST_FLOW_OK) {
  1150         if ((h.i_type == 'V') && (h.i_keyframe == 0)) {
  1151             frame_index_data *f = g_new0(frame_index_data, 1);
  1152 
  1153             f->offset = nuv->priv->offset - 12;
  1154             f->timecode = h.i_timecode * GST_MSECOND;
  1155 
  1156             nuv->priv->index = g_slist_append(nuv->priv->index, f);
  1157         }
  1158         if (h.i_type != 'R') {
  1159             nuv->priv->offset += h.i_length;
  1160             if (h.i_type == 'A' || h.i_type == 'V')
  1161                 nuv->priv->duration_time = h.i_timecode * GST_MSECOND;
  1162         }
  1163     }
  1164     GST_DEBUG_OBJECT(nuv,
  1165                      "CREATING INDEX: DONE : DURATION Bytes/Sec: %"
  1166                      G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
  1167                      nuv->priv->offset, nuv->priv->duration_time);
  1168 
  1169     nuv->priv->duration_bytes = nuv->priv->offset;
  1170     nuv->priv->offset = nuv->priv->header_lengh;
  1171 
  1172     msg =
  1173         gst_message_new_duration(GST_OBJECT(nuv), GST_FORMAT_TIME,
  1174                                  nuv->priv->duration_time);
  1175     gst_element_post_message(GST_ELEMENT(nuv), msg);
  1176 }
  1177 
  1178 static          GstFlowReturn
  1179 gst_nuv_demux_play(GstPad * pad)
  1180 {
  1181     GstFlowReturn   res = GST_FLOW_OK;
  1182     GstNuvDemux    *nuv = GST_NUV_DEMUX(GST_PAD_PARENT(pad));
  1183 
  1184     switch (nuv->priv->state) {
  1185     case GST_NUV_DEMUX_START:
  1186         res = gst_nuv_demux_stream_file_header(nuv);
  1187         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1188             goto pause;
  1189         }
  1190         break;
  1191 
  1192     case GST_NUV_DEMUX_HEADER_DATA:
  1193         res = gst_nuv_demux_stream_header_data(nuv);
  1194         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1195             goto pause;
  1196         }
  1197         break;
  1198 
  1199     case GST_NUV_DEMUX_EXTRA_DATA:
  1200         res = gst_nuv_demux_stream_extra_data(nuv);
  1201         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1202             goto pause;
  1203         }
  1204         break;
  1205 
  1206     case GST_NUV_DEMUX_MPEG_DATA:
  1207         res = gst_nuv_demux_stream_mpeg_data(nuv);
  1208         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1209             goto pause;
  1210         }
  1211         break;
  1212 
  1213     case GST_NUV_DEMUX_EXTEND_HEADER:
  1214         res = gst_nuv_demux_stream_extend_header(nuv);
  1215         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1216             goto pause;
  1217         }
  1218         break;
  1219 
  1220     case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
  1221         res = gst_nuv_demux_stream_extend_header_data(nuv);
  1222         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1223             goto pause;
  1224         }
  1225         // store file header size
  1226         nuv->priv->header_lengh = nuv->priv->offset;
  1227         break;
  1228 
  1229     case GST_NUV_DEMUX_INDEX_CREATE:
  1230         if ((nuv->priv->mode == NUV_PULL_MODE) && (!nuv->priv->new_file)) {
  1231             gst_nuv_demux_create_seek_index(nuv);
  1232         }
  1233 
  1234     case GST_NUV_DEMUX_FRAME_HEADER:
  1235         res = gst_nuv_demux_read_head_frame(nuv);
  1236         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1237             goto pause;
  1238         }
  1239         break;
  1240 
  1241     case GST_NUV_DEMUX_MOVI:
  1242         res = gst_nuv_demux_stream_data(nuv);
  1243         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
  1244             goto pause;
  1245         }
  1246         break;
  1247 
  1248     case GST_NUV_DEMUX_INVALID_DATA:
  1249         goto pause;
  1250         break;
  1251     default:
  1252         g_assert_not_reached();
  1253     }
  1254 
  1255     return GST_FLOW_OK;
  1256 
  1257   pause:
  1258     GST_LOG_OBJECT(nuv, "pausing task, reason %s", gst_flow_get_name(res));
  1259     gst_pad_pause_task(nuv->priv->sinkpad);
  1260 
  1261     if (res == GST_FLOW_ERROR_EOS) {
  1262         gst_nuv_demux_send_eos(nuv);
  1263         nuv->priv->eos = TRUE;
  1264         res = GST_FLOW_OK;
  1265     }
  1266 
  1267     if (GST_FLOW_IS_FATAL(res)) {
  1268         GST_ELEMENT_ERROR(nuv, STREAM, FAILED,
  1269                           (_("Internal data stream error.")),
  1270                           ("streaming stopped, reason %s",
  1271                            gst_flow_get_name(res)));
  1272 
  1273         gst_nuv_demux_send_eos(nuv);
  1274     }
  1275     return res;
  1276 }
  1277 
  1278 static void
  1279 gst_nuv_demux_send_eos(GstNuvDemux * nuv)
  1280 {
  1281     gst_element_post_message(GST_ELEMENT(nuv),
  1282                              gst_message_new_segment_done(GST_OBJECT(nuv),
  1283                                                           GST_FORMAT_TIME,
  1284                                                           -1));
  1285 
  1286     if (nuv->priv->src_video_pad)
  1287         gst_pad_push_event(nuv->priv->src_video_pad, gst_event_new_eos());
  1288     if (nuv->priv->src_audio_pad)
  1289         gst_pad_push_event(nuv->priv->src_audio_pad, gst_event_new_eos());
  1290 }
  1291 
  1292 static          GstFlowReturn
  1293 gst_nuv_demux_read_bytes(GstNuvDemux * nuv, guint64 size, gboolean move,
  1294                          GstBuffer ** buffer)
  1295 {
  1296     GstFlowReturn   ret = GST_FLOW_OK;
  1297 
  1298     if (size == 0) {
  1299         return ret;
  1300     }
  1301 
  1302     if (nuv->priv->mode == NUV_PULL_MODE) {
  1303         ret =
  1304             gst_pad_pull_range(nuv->priv->sinkpad, nuv->priv->offset, size,
  1305                                buffer);
  1306         if (ret == GST_FLOW_OK) {
  1307             if (move) {
  1308                 nuv->priv->offset += size;
  1309             }
  1310             /*
  1311              * got eos 
  1312              */
  1313         } else if (ret == GST_FLOW_UNEXPECTED) {
  1314             return GST_FLOW_ERROR_EOS;
  1315         }
  1316     } else {
  1317         if (gst_adapter_available(nuv->priv->adapter) < size) {
  1318             nuv->priv->more_data = TRUE;
  1319             return GST_FLOW_ERROR_NO_DATA;
  1320         }
  1321         if (move) {
  1322             *buffer = gst_adapter_take_buffer(nuv->priv->adapter, size);
  1323         } else {
  1324             guint8         *data = NULL;
  1325             data = (guint8 *) gst_adapter_peek(nuv->priv->adapter, size);
  1326             *buffer = gst_buffer_new();
  1327             gst_buffer_set_data(*buffer, data, size);
  1328         }
  1329     }
  1330     return ret;
  1331 }
  1332 
  1333 static          GstFlowReturn
  1334 gst_nuv_demux_move_bytes(GstNuvDemux * nuv, guint64 size)
  1335 {
  1336     GstFlowReturn   ret = GST_FLOW_OK;
  1337 
  1338     if (size == 0) {
  1339         return ret;
  1340     }
  1341 
  1342     if (nuv->priv->mode == NUV_PULL_MODE) {
  1343         nuv->priv->offset += size;
  1344     } else {
  1345         if (gst_adapter_available(nuv->priv->adapter) < size) {
  1346             nuv->priv->more_data = TRUE;
  1347             return GST_FLOW_ERROR_NO_DATA;
  1348         }
  1349         gst_adapter_flush(nuv->priv->adapter, size);
  1350     }
  1351     return ret;
  1352 }
  1353 
  1354 static          gboolean
  1355 gst_nuv_demux_sink_activate(GstPad * sinkpad)
  1356 {
  1357     gboolean        res = TRUE;
  1358     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
  1359 
  1360     if (gst_pad_check_pull_range(sinkpad)) {
  1361         gst_adapter_clear(nuv->priv->adapter);
  1362         res = gst_pad_activate_pull(sinkpad, TRUE);
  1363     } else {
  1364         gst_adapter_clear(nuv->priv->adapter);
  1365         res = gst_pad_activate_push(sinkpad, TRUE);
  1366     }
  1367 
  1368     g_object_unref(nuv);
  1369     return res;
  1370 }
  1371 
  1372 static          gboolean
  1373 gst_nuv_demux_sink_activate_pull(GstPad * sinkpad, gboolean active)
  1374 {
  1375     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
  1376 
  1377     if (active) {
  1378         GST_DEBUG_OBJECT(nuv, "activating pull function");
  1379         nuv->priv->mode = NUV_PULL_MODE;
  1380         gst_adapter_clear(nuv->priv->adapter);
  1381 
  1382         gst_pad_start_task(sinkpad, (GstTaskFunction) gst_nuv_demux_loop,
  1383                            sinkpad);
  1384     } else {
  1385         GST_DEBUG_OBJECT(nuv, "deactivating pull function");
  1386         gst_pad_stop_task(sinkpad);
  1387     }
  1388     gst_object_unref(nuv);
  1389 
  1390     return TRUE;
  1391 }
  1392 
  1393 static          gboolean
  1394 gst_nuv_demux_sink_activate_push(GstPad * pad, gboolean active)
  1395 {
  1396     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1397 
  1398     if (active) {
  1399         nuv->priv->mode = NUV_PUSH_MODE;
  1400         gst_adapter_clear(nuv->priv->adapter);
  1401 
  1402         GST_DEBUG_OBJECT(nuv, "activating push/chain function");
  1403     } else {
  1404         GST_DEBUG_OBJECT(nuv, "deactivating push/chain function");
  1405     }
  1406 
  1407     gst_object_unref(nuv);
  1408 
  1409     return TRUE;
  1410 }
  1411 
  1412 static frame_index_data *
  1413 gst_nuv_demux_do_seek_index(GstNuvDemux * nuv, gint64 seek_pos,
  1414                             gint64 segment_stop, GstFormat format)
  1415 {
  1416     GSList         *l;
  1417     frame_index_data *ret = NULL;
  1418 
  1419     if (nuv->priv->index == NULL) {
  1420         return NULL;
  1421     }
  1422 
  1423     /*
  1424      * find keyframe closest to the requested position 
  1425      */
  1426     for (l = nuv->priv->index; l != NULL; l = l->next) {
  1427         frame_index_data *f = (frame_index_data *) l->data;
  1428         gint64          pos = 0;
  1429 
  1430         if (format == GST_FORMAT_BYTES) {
  1431             pos = f->offset;
  1432         } else if (format == GST_FORMAT_TIME) {
  1433             pos = f->timecode;
  1434         } else {
  1435             return NULL;
  1436         }
  1437 
  1438         if (pos >= seek_pos) {
  1439             ret = f;
  1440             break;
  1441         }
  1442 
  1443         if ((segment_stop != -1) && (segment_stop != GST_CLOCK_TIME_NONE)
  1444             && (pos > segment_stop)) {
  1445             break;
  1446         }
  1447     }
  1448 
  1449     return ret;
  1450 }
  1451 
  1452 static          gboolean
  1453 gst_nuv_demux_do_seek(GstNuvDemux * nuv, GstEvent * event)
  1454 {
  1455     gdouble         rate;
  1456     GstFormat       format;
  1457     GstSeekFlags    flags;
  1458     GstSeekType     cur_type;
  1459     gint64          cur;
  1460     GstSeekType     stop_type;
  1461     gint64          stop;
  1462     gboolean        flush;
  1463     frame_index_data *entry;
  1464     gint64          segment_start;
  1465     gint64          segment_stop;
  1466     GstEvent       *newsegment_event;
  1467 
  1468     if (nuv->priv->eos) {
  1469         return FALSE;
  1470     }
  1471 
  1472     if (nuv->priv->mode == NUV_PUSH_MODE) {
  1473         return FALSE;
  1474     }
  1475 
  1476 
  1477     gst_event_parse_seek(event, &rate, &format, &flags,
  1478                          &cur_type, &cur, &stop_type, &stop);
  1479 
  1480 
  1481 
  1482     /*
  1483      * if (format == GST_FORMAT_TIME) { GST_DEBUG_OBJECT (nuv, "Can only
  1484      * seek on BYTES"); return FALSE; } 
  1485      */
  1486 
  1487     if (rate <= 0.0) {
  1488         GST_DEBUG_OBJECT(nuv, "Can only seek with positive rate");
  1489         return FALSE;
  1490     }
  1491 
  1492     if (cur_type == GST_SEEK_TYPE_SET) {
  1493         GST_OBJECT_LOCK(nuv);
  1494         if (gst_nuv_demux_do_seek_index(nuv, cur, -1, format) == NULL) {
  1495             GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
  1496             GST_OBJECT_UNLOCK(nuv);
  1497             return FALSE;
  1498         }
  1499         GST_OBJECT_UNLOCK(nuv);
  1500     }
  1501 
  1502     flush = !!(flags & GST_SEEK_FLAG_FLUSH);
  1503 
  1504     if (flush) {
  1505         gst_pad_push_event(nuv->priv->sinkpad,
  1506                            gst_event_new_flush_start());
  1507         if (nuv->priv->src_video_pad != NULL) {
  1508             gst_pad_push_event(nuv->priv->src_video_pad,
  1509                                gst_event_new_flush_start());
  1510         }
  1511 
  1512         if (nuv->priv->src_audio_pad != NULL) {
  1513             gst_pad_push_event(nuv->priv->src_audio_pad,
  1514                                gst_event_new_flush_start());
  1515         }
  1516     } else {
  1517         gst_pad_pause_task(nuv->priv->sinkpad);
  1518     }
  1519 
  1520     GST_PAD_STREAM_LOCK(nuv->priv->sinkpad);
  1521     GST_OBJECT_LOCK(nuv);
  1522 
  1523 
  1524     if (cur == GST_CLOCK_TIME_NONE)
  1525         cur = 0;
  1526     if (stop == GST_CLOCK_TIME_NONE)
  1527         stop = nuv->priv->duration_time;
  1528 
  1529     if (cur_type == GST_SEEK_TYPE_SET)
  1530         segment_start = cur;
  1531     else if (cur_type == GST_SEEK_TYPE_CUR)
  1532         segment_start = nuv->priv->segment_start + cur;
  1533     else
  1534         segment_start = nuv->priv->segment_start;
  1535 
  1536     if (stop_type == GST_SEEK_TYPE_SET)
  1537         segment_stop = stop;
  1538     else if (stop_type == GST_SEEK_TYPE_CUR)
  1539         segment_stop = nuv->priv->segment_stop + stop;
  1540     else
  1541         segment_stop = nuv->priv->segment_stop;
  1542 
  1543     segment_start = CLAMP(segment_start, 0, nuv->priv->duration_time);
  1544     segment_stop = CLAMP(segment_stop, 0, nuv->priv->duration_time);
  1545 
  1546     entry = gst_nuv_demux_do_seek_index(nuv, segment_start,
  1547                                         segment_stop, format);
  1548 
  1549     if (entry == NULL) {
  1550         GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
  1551         goto seek_error;
  1552     }
  1553 
  1554     segment_start = entry->timecode;
  1555 
  1556     nuv->priv->segment_start = segment_start;
  1557     nuv->priv->segment_stop = segment_stop;
  1558 
  1559     GST_OBJECT_UNLOCK(nuv);
  1560 
  1561     if (!nuv->priv->eos) {
  1562         GstMessage     *msg;
  1563         msg =
  1564             gst_message_new_segment_start(GST_OBJECT(nuv), GST_FORMAT_TIME,
  1565                                           nuv->priv->segment_start);
  1566 
  1567         gst_element_post_message(GST_ELEMENT(nuv), msg);
  1568     }
  1569 
  1570     GST_DEBUG_OBJECT(nuv,
  1571                      "NEW SEGMENT START %" G_GUINT64_FORMAT ", STOP %"
  1572                      G_GUINT64_FORMAT, segment_start, segment_stop);
  1573     newsegment_event =
  1574         gst_event_new_new_segment(FALSE, rate, GST_FORMAT_TIME,
  1575                                   segment_start, segment_stop,
  1576                                   segment_start);
  1577 
  1578 
  1579     if (flush) {
  1580         if (nuv->priv->src_video_pad != NULL) {
  1581             gst_pad_push_event(nuv->priv->src_video_pad,
  1582                                gst_event_new_flush_stop());
  1583         }
  1584 
  1585         if (nuv->priv->src_audio_pad != NULL) {
  1586             gst_pad_push_event(nuv->priv->src_audio_pad,
  1587                                gst_event_new_flush_stop());
  1588         }
  1589 
  1590         gst_pad_push_event(nuv->priv->sinkpad, gst_event_new_flush_stop());
  1591     }
  1592 
  1593 
  1594     if (nuv->priv->src_video_pad != NULL) {
  1595         gst_pad_push_event(nuv->priv->src_video_pad,
  1596                            gst_event_ref(newsegment_event));
  1597     }
  1598     if (nuv->priv->src_audio_pad != NULL) {
  1599         gst_pad_push_event(nuv->priv->src_audio_pad,
  1600                            gst_event_ref(newsegment_event));
  1601     }
  1602 
  1603     gst_event_unref(newsegment_event);
  1604 
  1605     nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
  1606     nuv->priv->offset = entry->offset;
  1607 
  1608     gst_pad_start_task(nuv->priv->sinkpad,
  1609                        (GstTaskFunction) gst_nuv_demux_loop,
  1610                        nuv->priv->sinkpad);
  1611 
  1612     GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
  1613     return TRUE;
  1614 
  1615   seek_error:
  1616     GST_DEBUG_OBJECT(nuv, "Got a seek error");
  1617     GST_OBJECT_UNLOCK(nuv);
  1618     GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
  1619     return FALSE;
  1620 
  1621 }
  1622 
  1623 static          gboolean
  1624 gst_nuv_demux_srcpad_event(GstPad * pad, GstEvent * event)
  1625 {
  1626     gboolean        res = FALSE;
  1627     GstNuvDemux    *nuv;
  1628 
  1629     nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1630 
  1631     switch (GST_EVENT_TYPE(event)) {
  1632     case GST_EVENT_SEEK:
  1633         res = gst_nuv_demux_do_seek(nuv, event);
  1634         break;
  1635     default:
  1636         res = FALSE;
  1637         break;
  1638     }
  1639 
  1640     gst_object_unref(nuv);
  1641     return res;
  1642 }
  1643 
  1644 static          gboolean
  1645 gst_nuv_demux_sink_event(GstPad * pad, GstEvent * event)
  1646 {
  1647     gboolean        res = FALSE;
  1648     GstNuvDemux    *nuv;
  1649 
  1650     nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1651 
  1652     switch (GST_EVENT_TYPE(event)) {
  1653         case GST_EVENT_NEWSEGMENT:
  1654             GST_PAD_STREAM_LOCK(pad);
  1655             gst_nuv_demux_reset(nuv);
  1656             GST_PAD_STREAM_UNLOCK(pad);
  1657 
  1658             //res = gst_pad_event_default(pad, event);
  1659             res = TRUE;
  1660             break;
  1661         default:
  1662             res = gst_pad_event_default(pad, event);
  1663             break;
  1664     }
  1665 
  1666     return res;
  1667 }
  1668 
  1669 static          GstFlowReturn
  1670 gst_nuv_demux_chain(GstPad * pad, GstBuffer * buf)
  1671 {
  1672     GstFlowReturn   ret = GST_FLOW_OK;
  1673     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
  1674 
  1675     if (nuv->priv->mode != NUV_PUSH_MODE)
  1676         return ret;
  1677 
  1678     gst_adapter_push(nuv->priv->adapter, buf);
  1679 
  1680     while ((ret == GST_FLOW_OK) && (nuv->priv->more_data == FALSE)) {
  1681         ret = gst_nuv_demux_play(pad);
  1682     }
  1683 
  1684     nuv->priv->more_data = FALSE;
  1685     gst_object_unref(nuv);
  1686 
  1687     return ret;
  1688 }
  1689 
  1690 static void
  1691 gst_nuv_demux_loop(GstPad * pad)
  1692 {
  1693     gst_nuv_demux_play(pad);
  1694 }
  1695 
  1696 static void
  1697 gst_nuv_demux_index_free(gpointer data, gpointer user_data)
  1698 {
  1699     g_free(data);
  1700 }
  1701 
  1702 static void
  1703 gst_nuv_demux_reset(GstNuvDemux * nuv)
  1704 {
  1705     nuv->priv->eos = FALSE;
  1706     nuv->priv->more_data = FALSE;
  1707     nuv->priv->state = GST_NUV_DEMUX_START;
  1708     nuv->priv->mode = NUV_PUSH_MODE;
  1709     nuv->priv->offset = 0;
  1710     nuv->priv->time_start = 0;
  1711     nuv->priv->time_qos = GST_CLOCK_TIME_NONE;
  1712     nuv->priv->duration_bytes = GST_CLOCK_TIME_NONE;
  1713     nuv->priv->duration_time = GST_CLOCK_TIME_NONE;
  1714     nuv->priv->last_video_return = GST_FLOW_OK;
  1715     nuv->priv->last_audio_return = GST_FLOW_OK;
  1716     nuv->priv->header_lengh = 0;
  1717     nuv->priv->segment_stop = GST_CLOCK_TIME_NONE;
  1718     nuv->priv->segment_start = GST_CLOCK_TIME_NONE;
  1719     nuv->priv->new_file = FALSE;
  1720 
  1721     // clear index list
  1722     g_slist_foreach(nuv->priv->index, gst_nuv_demux_index_free, NULL);
  1723     g_slist_free(nuv->priv->index);
  1724     nuv->priv->index = NULL;
  1725 
  1726     gst_adapter_clear(nuv->priv->adapter);
  1727 
  1728     if (nuv->priv->mpeg_buffer != NULL) {
  1729         gst_buffer_unref(nuv->priv->mpeg_buffer);
  1730         nuv->priv->mpeg_buffer = NULL;
  1731     }
  1732 }
  1733 
  1734 static void
  1735 gst_nuv_demux_destoy_src_pad(GstNuvDemux * nuv)
  1736 {
  1737     if (nuv->priv->src_video_pad) {
  1738         gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_video_pad);
  1739         nuv->priv->src_video_pad = NULL;
  1740     }
  1741 
  1742     if (nuv->priv->src_audio_pad) {
  1743         gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_audio_pad);
  1744         nuv->priv->src_audio_pad = NULL;
  1745     }
  1746 }
  1747 
  1748 static          GstStateChangeReturn
  1749 gst_nuv_demux_change_state(GstElement * element, GstStateChange transition)
  1750 {
  1751     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  1752 
  1753     switch (transition) {
  1754     case GST_STATE_CHANGE_NULL_TO_READY:
  1755         gst_nuv_demux_reset(GST_NUV_DEMUX(element));
  1756         gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
  1757         break;
  1758     default:
  1759         break;
  1760     }
  1761 
  1762     ret =
  1763         GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
  1764     if (ret == GST_STATE_CHANGE_FAILURE) {
  1765         goto done;
  1766     }
  1767 
  1768 
  1769     switch (transition) {
  1770     case GST_STATE_CHANGE_READY_TO_NULL:
  1771         gst_nuv_demux_reset(GST_NUV_DEMUX(element));
  1772         gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
  1773         break;
  1774     default:
  1775         break;
  1776     }
  1777   done:
  1778     return ret;
  1779 }
  1780 
  1781 #if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
  1782 GstBuffer      *
  1783 gst_adapter_take_buffer(GstAdapter * adapter, guint nbytes)
  1784 {
  1785     GstBuffer      *buffer;
  1786     GstBuffer      *cur;
  1787     guint8         *data;
  1788 
  1789     g_return_val_if_fail(GST_IS_ADAPTER(adapter), NULL);
  1790     g_return_val_if_fail(nbytes > 0, NULL);
  1791 
  1792     GST_LOG_OBJECT(adapter, "taking buffer of %u bytes", nbytes);
  1793 
  1794     /*
  1795      * we don't have enough data, return NULL. This is unlikely as one
  1796      * usually does an _available() first instead of peeking a random
  1797      * size. 
  1798      */
  1799     if (G_UNLIKELY(nbytes > adapter->size))
  1800         return NULL;
  1801 
  1802     /*
  1803      * our head buffer has enough data left, return it 
  1804      */
  1805     cur = adapter->buflist->data;
  1806     if (GST_BUFFER_SIZE(cur) >= nbytes + adapter->skip) {
  1807         GST_LOG_OBJECT(adapter,
  1808                        "providing buffer of %d bytes via sub-buffer",
  1809                        nbytes);
  1810         buffer = gst_buffer_create_sub(cur, adapter->skip, nbytes);
  1811 
  1812         gst_adapter_flush(adapter, nbytes);
  1813 
  1814         return buffer;
  1815     }
  1816 
  1817     data = gst_adapter_take(adapter, nbytes);
  1818     if (data == NULL)
  1819         return NULL;
  1820 
  1821     buffer = gst_buffer_new();
  1822     GST_BUFFER_DATA(buffer) = data;
  1823     GST_BUFFER_MALLOCDATA(buffer) = data;
  1824     GST_BUFFER_SIZE(buffer) = nbytes;
  1825 
  1826     return buffer;
  1827 }
  1828 #endif
  1829 
  1830 static void
  1831 gst_nuv_typefind(GstTypeFind * tf, gpointer unused)
  1832 {
  1833     guint8         *data = gst_type_find_peek(tf, 0, 11);
  1834 
  1835     if (data) {
  1836         if (memcmp(data, "MythTVVideo", 11) == 0
  1837             || memcmp(data, "NuppelVideo", 11) == 0) {
  1838             gst_type_find_suggest(tf, GST_TYPE_FIND_MAXIMUM,
  1839                                   gst_caps_new_simple("video/x-nuv",
  1840                                                       NULL));
  1841         }
  1842     }
  1843 }
  1844 
  1845 static          gboolean
  1846 plugin_init(GstPlugin * plugin)
  1847 {
  1848     static gchar   *exts[] = { "nuv", NULL };
  1849 #ifdef ENABLE_NLS
  1850     setlocale(LC_ALL, "");
  1851     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
  1852 #endif                          /* ENABLE_NLS */
  1853 
  1854     if (!gst_element_register(plugin, "nuvdemux", GST_RANK_SECONDARY,
  1855                               GST_TYPE_NUV_DEMUX)) {
  1856         return FALSE;
  1857     }
  1858 
  1859     if (!gst_type_find_register(plugin, "video/x-nuv", GST_RANK_SECONDARY,
  1860                                 gst_nuv_typefind,
  1861                                 exts,
  1862                                 gst_caps_new_simple("video/x-nuv", NULL),
  1863                                 NULL, NULL)) {
  1864         GST_WARNING("can't register typefind");
  1865         return FALSE;
  1866     }
  1867 
  1868     return TRUE;
  1869 }
  1870 
  1871 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
  1872                   GST_VERSION_MINOR,
  1873                   "nuvdemux",
  1874                   "Demuxes and muxes audio and video",
  1875                   plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
  1876                   GST_PACKAGE_ORIGIN)