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