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