[svn r92] code review trunk
authorrenatofilho
Fri Nov 17 13:18:48 2006 +0000 (2006-11-17)
branchtrunk
changeset 916b1e210c250a
parent 90 f6a9705509a1
child 92 e594fc21deef
[svn r92] code review
gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c
gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.h
     1.1 --- a/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c	Fri Nov 17 13:09:12 2006 +0000
     1.2 +++ b/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.c	Fri Nov 17 13:18:48 2006 +0000
     1.3 @@ -56,11 +56,12 @@
     1.4  #include "glib/gi18n.h"
     1.5  #include "gstnuvdemux.h"
     1.6  
     1.7 +#define GST_NUV_DEMUX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_NUV_DEMUX, GstNuvDemuxPrivate))
     1.8 +
     1.9  GST_DEBUG_CATEGORY_STATIC (nuvdemux_debug);
    1.10  #define GST_CAT_DEFAULT nuvdemux_debug
    1.11 +#define GST_FLOW_ERROR_NO_DATA  -101
    1.12  
    1.13 -
    1.14 -#define GST_FLOW_ERROR_NO_DATA  -101
    1.15  enum
    1.16  {
    1.17     NUV_PUSH_MODE = 0,
    1.18 @@ -76,6 +77,155 @@
    1.19      "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
    1.20      "Rosfran Borges <rosfran.borges@indt.org.br>");
    1.21  
    1.22 +
    1.23 +/* file header */
    1.24 +typedef struct
    1.25 +{
    1.26 +    gchar id[12];       /* "NuppelVideo\0" or "MythTVVideo\0" */
    1.27 +    gchar version[5];    /* "x.xx\0" */
    1.28 +
    1.29 +    gint  i_width;
    1.30 +    gint  i_height;
    1.31 +    gint  i_width_desired;
    1.32 +    gint  i_height_desired;
    1.33 +
    1.34 +    gchar i_mode;            /* P progressive, I interlaced */
    1.35 +
    1.36 +    gdouble  d_aspect;       /* 1.0 squared pixel */
    1.37 +    gdouble  d_fps;
    1.38 +    //fps num/denom
    1.39 +    gint     i_fpsn;
    1.40 +    gint     i_fpsd;
    1.41 +
    1.42 +    gint     i_video_blocks; /* 0 no video, -1 unknown */
    1.43 +    gint     i_audio_blocks;
    1.44 +    gint     i_text_blocks;
    1.45 +
    1.46 +    gint     i_keyframe_distance;
    1.47 +
    1.48 +} nuv_header;
    1.49 +
    1.50 +/* frame header */
    1.51 +typedef struct
    1.52 +{
    1.53 +    gchar i_type;        /* A: audio, V: video, S: sync; T: test
    1.54 +                           R: Seekpoint (string:RTjjjjjjjj)
    1.55 +                           D: Extra data for codec */
    1.56 +    gchar i_compression; /* V: 0 uncompressed
    1.57 +                              1 RTJpeg
    1.58 +                              2 RTJpeg+lzo
    1.59 +                              N black frame
    1.60 +                              L copy last
    1.61 +                           A: 0 uncompressed (44100 1-bits, 2ch)
    1.62 +                              1 lzo
    1.63 +                              2 layer 2
    1.64 +                              3 layer 3
    1.65 +                              F flac
    1.66 +                              S shorten
    1.67 +                              N null frame loudless
    1.68 +                              L copy last
    1.69 +                            S: B audio and vdeo sync point
    1.70 +                               A audio sync info (timecode == effective
    1.71 +                                    dsp frequency*100)
    1.72 +                               V next video sync (timecode == next video
    1.73 +                                    frame num)
    1.74 +                               S audio,video,text correlation */
    1.75 +    gchar i_keyframe;    /* 0 keyframe, else no no key frame */
    1.76 +    guint8 i_filters;  /* 0x01: gauss 5 pixel (8,2,2,2,2)/16
    1.77 +                           0x02: gauss 5 pixel (8,1,1,1,1)/12
    1.78 +                           0x04: cartoon filter */
    1.79 +
    1.80 +    gint32 i_timecode;     /* ms */
    1.81 +
    1.82 +    gint i_length;       /* V,A,T: length of following data
    1.83 +                           S: length of packet correl */
    1.84 +} nuv_frame_header;
    1.85 +
    1.86 +/* FIXME Not sure of this one */
    1.87 +typedef struct
    1.88 +{
    1.89 +    gint             i_version;
    1.90 +    guint32		     i_video_fcc;
    1.91 +
    1.92 +    guint32		     i_audio_fcc;
    1.93 +    gint             i_audio_sample_rate;
    1.94 +    gint             i_audio_bits_per_sample;
    1.95 +    gint             i_audio_channels;
    1.96 +    gint             i_audio_compression_ratio;
    1.97 +    gint             i_audio_quality;
    1.98 +    gint             i_rtjpeg_quality;
    1.99 +    gint             i_rtjpeg_luma_filter;
   1.100 +    gint             i_rtjpeg_chroma_filter;
   1.101 +    gint             i_lavc_bitrate;
   1.102 +    gint             i_lavc_qmin;
   1.103 +    gint             i_lavc_qmax;
   1.104 +    gint             i_lavc_maxqdiff;
   1.105 +    gint64         	 i_seekable_offset;
   1.106 +    gint64           i_keyframe_adjust_offset;
   1.107 +
   1.108 +} nuv_extended_header;
   1.109 +
   1.110 +typedef enum {
   1.111 +  GST_NUV_DEMUX_START,
   1.112 +  GST_NUV_DEMUX_HEADER_DATA,
   1.113 +  GST_NUV_DEMUX_EXTRA_DATA,
   1.114 +  GST_NUV_DEMUX_MPEG_DATA,
   1.115 +  GST_NUV_DEMUX_EXTEND_HEADER,
   1.116 +  GST_NUV_DEMUX_EXTEND_HEADER_DATA,
   1.117 +  GST_NUV_DEMUX_FRAME_HEADER,
   1.118 +  GST_NUV_DEMUX_MOVI,
   1.119 +  GST_NUV_DEMUX_INVALID_DATA
   1.120 +} GstNuvDemuxState;
   1.121 +
   1.122 +struct _GstNuvDemuxPrivate {
   1.123 +  /* used for indicate the mode */
   1.124 +  guint         mode;
   1.125 +
   1.126 +  /* used on push mode */
   1.127 +  GstAdapter    *adapter;
   1.128 +
   1.129 +  /* pads */
   1.130 +  GstPad        *sinkpad;
   1.131 +  GstPad        *src_video_pad;
   1.132 +  GstPad        *src_audio_pad;
   1.133 +
   1.134 +  /* Flow control */
   1.135 +  GstFlowReturn last_video_return;
   1.136 +  GstFlowReturn last_audio_return;
   1.137 +
   1.138 +  /* NUV decoding state */
   1.139 +  GstNuvDemuxState  state;
   1.140 +  GstSegment        segment;
   1.141 +  guint64           last_update;
   1.142 +  guint64           offset;
   1.143 +  guint64           streamer_offset;
   1.144 +
   1.145 +  /* duration information */
   1.146 +  gint64            duration_bytes;
   1.147 +  gint64            duration_time;
   1.148 +  gint64            duration_average;
   1.149 +
   1.150 +  /* segment control info */
   1.151 +  gboolean          new_audio_segment;
   1.152 +  gboolean          new_video_segment;
   1.153 +
   1.154 +  /* Mpeg ExtraData */
   1.155 +  guint64       mpeg_data_size;
   1.156 +  GstBuffer     *mpeg_buffer;
   1.157 +
   1.158 +  /* Headers */
   1.159 +  nuv_header *h;
   1.160 +  nuv_extended_header *eh;
   1.161 +  nuv_frame_header *fh;
   1.162 +
   1.163 +  /* anothers info */
   1.164 +  gint64            time_start;
   1.165 +  gint64            time_diff;
   1.166 +  gint64            time_qos;
   1.167 +  guint64           last_frame_time;
   1.168 +};
   1.169 +
   1.170 +
   1.171  static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
   1.172      GST_PAD_SINK,
   1.173      GST_PAD_ALWAYS,
   1.174 @@ -93,6 +243,7 @@
   1.175      GST_PAD_SOMETIMES,
   1.176      GST_STATIC_CAPS_ANY);
   1.177  
   1.178 +static void gst_nuv_demux_dispose (GObject * object);
   1.179  static void gst_nuv_demux_finalize (GObject * object);
   1.180  static GstStateChangeReturn gst_nuv_demux_change_state (GstElement * element,
   1.181      GstStateChange transition);
   1.182 @@ -101,18 +252,25 @@
   1.183  static GstFlowReturn gst_nuv_demux_play (GstPad * pad);
   1.184  static gboolean gst_nuv_demux_sink_activate_pull (GstPad * sinkpad,
   1.185      gboolean active);
   1.186 -static gboolean gst_nuv_demux_sink_activate_push (GstPad * pad, 
   1.187 +static gboolean gst_nuv_demux_sink_activate_push (GstPad * pad,
   1.188      gboolean active);
   1.189  static gboolean gst_nuv_demux_sink_activate (GstPad * sinkpad);
   1.190 +static gboolean gst_nuv_demux_sink_event    (GstPad *pad, GstEvent *event);
   1.191  static GstFlowReturn gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size,
   1.192      gboolean move, GstBuffer ** buffer);
   1.193  static void gst_nuv_demux_reset (GstNuvDemux * nuv);
   1.194  static void gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv);
   1.195  static void gst_nuv_demux_send_eos (GstNuvDemux * nuv);
   1.196 +static void gst_nuv_demux_update_duration (GstNuvDemux *nuv, guint64 current_timestamp);
   1.197 +static gint64 gst_nuv_demux_get_bytes_duration (GstNuvDemux *nuv);
   1.198 +static gint64 gst_nuv_demux_get_time_duration (GstNuvDemux *nuv);
   1.199  
   1.200 -/* GObject methods */
   1.201 +
   1.202  GST_BOILERPLATE (GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
   1.203  
   1.204 +/******************************************************************************
   1.205 + * Utils function
   1.206 + ******************************************************************************/
   1.207  #if G_BYTE_ORDER == G_BIG_ENDIAN
   1.208  static inline gdouble
   1.209  _gdouble_swap_le_be (gdouble * d)
   1.210 @@ -133,7 +291,7 @@
   1.211  #define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
   1.212  #endif /* G_BYTE_ORDER != G_BIG_ENDIAN */
   1.213  
   1.214 -static void 
   1.215 +static void
   1.216  double2fraction (double in, int *num, int *denom)
   1.217  {
   1.218      if (in == 29.97) {
   1.219 @@ -152,6 +310,8 @@
   1.220      }
   1.221  }
   1.222  
   1.223 +/* GObject Functions */
   1.224 +
   1.225  static void
   1.226  gst_nuv_demux_base_init (gpointer klass)
   1.227  {
   1.228 @@ -179,54 +339,55 @@
   1.229  
   1.230    parent_class = g_type_class_peek_parent (klass);
   1.231  
   1.232 +  gobject_class->dispose = gst_nuv_demux_dispose;
   1.233    gobject_class->finalize = gst_nuv_demux_finalize;
   1.234    gstelement_class->change_state = gst_nuv_demux_change_state;
   1.235 +
   1.236 +  g_type_class_add_private (gobject_class, sizeof (GstNuvDemuxPrivate));
   1.237  }
   1.238  
   1.239  static void
   1.240  gst_nuv_demux_init (GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
   1.241  {
   1.242 -  nuv->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
   1.243 +  nuv->priv = GST_NUV_DEMUX_GET_PRIVATE (nuv);
   1.244 +  nuv->priv->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
   1.245 +  gst_pad_set_activate_function (nuv->priv->sinkpad, gst_nuv_demux_sink_activate);
   1.246 +  gst_pad_set_activatepull_function (nuv->priv->sinkpad,
   1.247 +      gst_nuv_demux_sink_activate_pull);
   1.248 +  gst_pad_set_activatepush_function (nuv->priv->sinkpad,
   1.249 +      gst_nuv_demux_sink_activate_push);
   1.250 +  gst_pad_set_chain_function (nuv->priv->sinkpad,
   1.251 +      GST_DEBUG_FUNCPTR (gst_nuv_demux_chain));
   1.252 +  gst_pad_set_event_function (nuv->priv->sinkpad,
   1.253 +      gst_nuv_demux_sink_event);
   1.254 +  gst_element_add_pad (GST_ELEMENT (nuv), nuv->priv->sinkpad);
   1.255  
   1.256 -  gst_pad_set_activate_function (nuv->sinkpad, gst_nuv_demux_sink_activate);
   1.257 +  nuv->priv->new_audio_segment = TRUE;
   1.258 +  nuv->priv->new_video_segment = TRUE;
   1.259  
   1.260 -  gst_pad_set_activatepull_function (nuv->sinkpad,
   1.261 -      gst_nuv_demux_sink_activate_pull);
   1.262 +  gst_nuv_demux_reset (nuv);
   1.263 +}
   1.264  
   1.265 -  gst_pad_set_activatepush_function (nuv->sinkpad, 
   1.266 -      gst_nuv_demux_sink_activate_push);
   1.267 +static void
   1.268 +gst_nuv_demux_dispose (GObject * object)
   1.269 +{
   1.270 +  GstNuvDemux *nuv = GST_NUV_DEMUX (object);
   1.271  
   1.272 -  gst_pad_set_chain_function (nuv->sinkpad,
   1.273 -      GST_DEBUG_FUNCPTR (gst_nuv_demux_chain));
   1.274 +  if (nuv->priv->mpeg_buffer != NULL) {
   1.275 +    gst_buffer_unref (nuv->priv->mpeg_buffer);
   1.276 +  }
   1.277  
   1.278 -  gst_element_add_pad (GST_ELEMENT (nuv), nuv->sinkpad);
   1.279 -  
   1.280 -  nuv->adapter = NULL;
   1.281 -  nuv->mpeg_buffer = NULL;
   1.282 -  nuv->h = NULL;
   1.283 -  nuv->eh = NULL;
   1.284 -  nuv->fh = NULL;
   1.285 +  gst_nuv_demux_reset (GST_NUV_DEMUX (object));
   1.286 +  gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (object));
   1.287  
   1.288 -  nuv->new_audio_segment = TRUE;
   1.289 -  nuv->new_video_segment = TRUE;
   1.290 -  
   1.291 -  gst_nuv_demux_reset (nuv);
   1.292 +  if (nuv->priv->adapter != NULL) {
   1.293 +    gst_object_unref (nuv->priv->adapter);
   1.294 +  }
   1.295  }
   1.296  
   1.297  static void
   1.298  gst_nuv_demux_finalize (GObject * object)
   1.299  {
   1.300 -  GstNuvDemux *nuv = GST_NUV_DEMUX (object);
   1.301 -
   1.302 -  if (nuv->mpeg_buffer != NULL) {
   1.303 -    gst_buffer_unref (nuv->mpeg_buffer);
   1.304 -  }
   1.305 -  
   1.306 -  gst_nuv_demux_destoy_src_pad (nuv);
   1.307 -  gst_nuv_demux_reset (nuv);
   1.308 -  if (nuv->adapter != NULL) {
   1.309 -    gst_object_unref (nuv->adapter);
   1.310 -  }
   1.311    G_OBJECT_CLASS (parent_class)->finalize (object);
   1.312  }
   1.313  
   1.314 @@ -274,10 +435,11 @@
   1.315  static GstFlowReturn
   1.316  gst_nuv_demux_stream_header_data (GstNuvDemux * nuv)
   1.317  {
   1.318 -  GstFlowReturn res = gst_nuv_demux_header_load (nuv, &nuv->h);
   1.319 +  GstFlowReturn res;
   1.320  
   1.321 +  res = gst_nuv_demux_header_load (nuv, &nuv->priv->h);
   1.322    if (res == GST_FLOW_OK)
   1.323 -    nuv->state = GST_NUV_DEMUX_EXTRA_DATA;
   1.324 +    nuv->priv->state = GST_NUV_DEMUX_EXTRA_DATA;
   1.325    return res;
   1.326  }
   1.327  
   1.328 @@ -296,10 +458,10 @@
   1.329    } else {
   1.330      if (strncmp ((gchar *) file_header->data, "MythTVVideo", 11) ||
   1.331          strncmp ((gchar *) file_header->data, "NuppelVideo", 11)) {
   1.332 -      nuv->state = GST_NUV_DEMUX_HEADER_DATA;
   1.333 +      nuv->priv->state = GST_NUV_DEMUX_HEADER_DATA;
   1.334      } else {
   1.335        GST_DEBUG_OBJECT (nuv, "error parsing file header");
   1.336 -      nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   1.337 +      nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
   1.338        res = GST_FLOW_ERROR;
   1.339      }
   1.340    }
   1.341 @@ -336,7 +498,7 @@
   1.342    h->i_filters = GPOINTER_TO_INT (data[3]);
   1.343    h->i_timecode = GST_READ_UINT32_LE (&data[4]);
   1.344    h->i_length = GST_READ_UINT32_LE (&data[8]);
   1.345 -  
   1.346 +
   1.347    GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
   1.348        h->i_type,
   1.349        h->i_compression ? h->i_compression : ' ',
   1.350 @@ -400,11 +562,15 @@
   1.351    gst_buffer_unref (buff);
   1.352    return res;
   1.353  }
   1.354 +
   1.355 +
   1.356 +/* Query Functions */
   1.357  static const GstQueryType *
   1.358  gst_nuv_demux_get_src_query_types (GstPad * pad)
   1.359  {
   1.360    static const GstQueryType src_types[] = {
   1.361      GST_QUERY_POSITION,
   1.362 +    GST_QUERY_DURATION,
   1.363      0
   1.364    };
   1.365  
   1.366 @@ -419,11 +585,23 @@
   1.367  
   1.368    switch (GST_QUERY_TYPE (query)) {
   1.369      case GST_QUERY_POSITION:
   1.370 -      if (GST_CLOCK_TIME_IS_VALID (nuv->last_frame_time)) {
   1.371 -        gst_query_set_position (query, GST_FORMAT_TIME,
   1.372 -            nuv->last_frame_time);
   1.373 +      if (GST_CLOCK_TIME_IS_VALID (nuv->priv->last_frame_time)) {
   1.374 +
   1.375 +        gst_query_set_position (query, GST_FORMAT_TIME, nuv->priv->last_frame_time);
   1.376          res = TRUE;
   1.377 -        GST_DEBUG_OBJECT (nuv, "POS %d", nuv->last_frame_time);
   1.378 +      }
   1.379 +      break;
   1.380 +    case GST_QUERY_DURATION:
   1.381 +      {
   1.382 +        gint64 duration = 0;
   1.383 +        duration = gst_nuv_demux_get_time_duration (nuv);
   1.384 +        if (duration == GST_CLOCK_TIME_NONE) {
   1.385 +            duration = nuv->priv->duration_average;
   1.386 +        }
   1.387 +        if (duration != GST_CLOCK_TIME_NONE) {
   1.388 +            gst_query_set_duration (query, GST_FORMAT_TIME, duration);
   1.389 +            res = TRUE;
   1.390 +        }
   1.391        }
   1.392        break;
   1.393      default:
   1.394 @@ -436,52 +614,48 @@
   1.395    return res;
   1.396  }
   1.397  
   1.398 -//TODO: create a function to control events and send to src pads
   1.399 +static GstPad*
   1.400 +gst_nuv_demux_create_pad (GstNuvDemux *nuv, GstCaps *caps, GstStaticPadTemplate *template, const gchar* name)
   1.401 +{
   1.402 +    GstPad *pad = NULL;
   1.403 +    pad = gst_pad_new_from_static_template (template, name);
   1.404 +    gst_pad_use_fixed_caps (pad);
   1.405 +    gst_pad_set_caps (pad, caps);
   1.406 +    gst_pad_set_active (pad, TRUE);
   1.407 +    gst_element_add_pad (GST_ELEMENT (nuv), pad);
   1.408 +
   1.409 +    return pad;
   1.410 +}
   1.411 +
   1.412  static void
   1.413  gst_nuv_demux_create_pads (GstNuvDemux * nuv)
   1.414  {
   1.415 -  if (nuv->h->i_video_blocks != 0) {
   1.416 +  if (nuv->priv->h->i_video_blocks != 0) {
   1.417      GstCaps *video_caps = NULL;
   1.418  
   1.419 -    nuv->src_video_pad =
   1.420 -        gst_pad_new_from_static_template (&video_src_template, "video_src");
   1.421 -
   1.422      video_caps = gst_caps_new_simple ("video/x-divx",
   1.423          "divxversion", G_TYPE_INT, 4,
   1.424 -        "width", G_TYPE_INT, nuv->h->i_width,
   1.425 -        "height", G_TYPE_INT, nuv->h->i_height,
   1.426 -        "framerate", GST_TYPE_FRACTION, nuv->h->i_fpsn, nuv->h->i_fpsd,
   1.427 -        "format", GST_TYPE_FOURCC, nuv->eh->i_video_fcc,
   1.428 +        "width", G_TYPE_INT, nuv->priv->h->i_width,
   1.429 +        "height", G_TYPE_INT, nuv->priv->h->i_height,
   1.430 +        "framerate", GST_TYPE_FRACTION, nuv->priv->h->i_fpsn, nuv->priv->h->i_fpsd,
   1.431 +        "format", GST_TYPE_FOURCC, nuv->priv->eh->i_video_fcc,
   1.432          "pixel-aspect-ratio", GST_TYPE_FRACTION,
   1.433 -        (gint) (nuv->h->d_aspect * 1000.0f), 1000, NULL);
   1.434 +        (gint) (nuv->priv->h->d_aspect * 1000.0f), 1000, NULL);
   1.435  
   1.436 -    gst_pad_use_fixed_caps (nuv->src_video_pad);
   1.437 -    gst_pad_set_caps (nuv->src_video_pad, video_caps);
   1.438 -    gst_pad_set_active (nuv->src_video_pad, TRUE);
   1.439 -    gst_pad_set_query_type_function (nuv->src_video_pad, gst_nuv_demux_get_src_query_types);
   1.440 -    gst_pad_set_query_function (nuv->src_video_pad, gst_nuv_demux_handle_src_query);
   1.441 -    gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
   1.442 +    nuv->priv->src_video_pad = gst_nuv_demux_create_pad (nuv, video_caps, &video_src_template, "video_src");
   1.443      gst_caps_unref (video_caps);
   1.444    }
   1.445  
   1.446 -  if (nuv->h->i_audio_blocks != 0) {
   1.447 +  if (nuv->priv->h->i_audio_blocks != 0) {
   1.448      GstCaps *audio_caps = NULL;
   1.449  
   1.450 -    nuv->src_audio_pad =
   1.451 -        gst_pad_new_from_static_template (&audio_src_template, "audio_src");
   1.452 +    audio_caps = gst_caps_new_simple ("audio/mpeg",
   1.453 +        "rate", G_TYPE_INT, nuv->priv->eh->i_audio_sample_rate,
   1.454 +        "format", GST_TYPE_FOURCC, nuv->priv->eh->i_audio_fcc,
   1.455 +        "channels", G_TYPE_INT, nuv->priv->eh->i_audio_channels,
   1.456 +        "mpegversion", G_TYPE_INT, nuv->priv->eh->i_version, NULL);
   1.457  
   1.458 -    audio_caps = gst_caps_new_simple ("audio/mpeg",
   1.459 -        "rate", G_TYPE_INT, nuv->eh->i_audio_sample_rate,
   1.460 -        "format", GST_TYPE_FOURCC, nuv->eh->i_audio_fcc,
   1.461 -        "channels", G_TYPE_INT, nuv->eh->i_audio_channels,
   1.462 -        "mpegversion", G_TYPE_INT, nuv->eh->i_version, NULL);
   1.463 -
   1.464 -    gst_pad_use_fixed_caps (nuv->src_audio_pad);
   1.465 -    gst_pad_set_caps (nuv->src_audio_pad, audio_caps);
   1.466 -    gst_pad_set_active (nuv->src_audio_pad, TRUE);
   1.467 -    gst_pad_set_query_type_function (nuv->src_video_pad, gst_nuv_demux_get_src_query_types);
   1.468 -    gst_pad_set_query_function (nuv->src_video_pad, gst_nuv_demux_handle_src_query);
   1.469 -    gst_element_add_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
   1.470 +    nuv->priv->src_audio_pad = gst_nuv_demux_create_pad (nuv, audio_caps, &audio_src_template, "audio_src");
   1.471      gst_caps_unref (audio_caps);
   1.472    }
   1.473  
   1.474 @@ -493,49 +667,53 @@
   1.475  {
   1.476    GstFlowReturn ret = GST_FLOW_OK;
   1.477  
   1.478 -  if (nuv->fh != NULL) 
   1.479 +  if (nuv->priv->fh != NULL)
   1.480    {
   1.481 -    g_free (nuv->fh);
   1.482 -    nuv->fh = NULL;
   1.483 +    g_free (nuv->priv->fh);
   1.484 +    nuv->priv->fh = NULL;
   1.485    }
   1.486 -  
   1.487 -  ret = gst_nuv_demux_frame_header_load (nuv, &nuv->fh);
   1.488 +
   1.489 +  ret = gst_nuv_demux_frame_header_load (nuv, &nuv->priv->fh);
   1.490    if (ret != GST_FLOW_OK)
   1.491      return ret;
   1.492  
   1.493 -  nuv->state = GST_NUV_DEMUX_MOVI;
   1.494 +  nuv->priv->state = GST_NUV_DEMUX_MOVI;
   1.495    return ret;
   1.496  }
   1.497  
   1.498  static gboolean
   1.499  gst_nuv_combine_flow (GstNuvDemux *nuv)
   1.500  {
   1.501 -    GstFlowReturn ret_video = nuv->last_video_return;
   1.502 -    GstFlowReturn ret_audio = nuv->last_audio_return;
   1.503 +    GstFlowReturn ret_video = nuv->priv->last_video_return;
   1.504 +    GstFlowReturn ret_audio = nuv->priv->last_audio_return;
   1.505  
   1.506      if ((ret_video != GST_FLOW_OK) &&
   1.507          (ret_audio != GST_FLOW_OK))
   1.508          return FALSE;
   1.509  
   1.510 -    if (GST_FLOW_IS_FATAL (nuv->last_video_return))
   1.511 +    if (GST_FLOW_IS_FATAL (ret_video))
   1.512          return FALSE;
   1.513  
   1.514 -    if (GST_FLOW_IS_FATAL (nuv->last_audio_return))
   1.515 +    if (GST_FLOW_IS_FATAL (ret_audio))
   1.516          return FALSE;
   1.517  
   1.518 -    return TRUE;    
   1.519 +    return TRUE;
   1.520  }
   1.521  
   1.522  static GstFlowReturn
   1.523  gst_nuv_demux_stream_data (GstNuvDemux * nuv)
   1.524  {
   1.525    GstFlowReturn ret = GST_FLOW_OK;
   1.526 +  GstPad *pad = NULL;
   1.527 +  guint64 timestamp;
   1.528    GstBuffer *buf = NULL;
   1.529 -  nuv_frame_header *h = nuv->fh;
   1.530 +  nuv_frame_header *h = NULL;
   1.531 +
   1.532 +  h = nuv->priv->fh;
   1.533  
   1.534    if (h->i_type == 'R')
   1.535      goto done;
   1.536 -    
   1.537 +
   1.538    if (h->i_length > 0) {
   1.539  	  ret = gst_nuv_demux_read_bytes (nuv, h->i_length, TRUE, &buf);
   1.540  	  if ((ret != GST_FLOW_OK) || (buf == NULL))
   1.541 @@ -543,81 +721,74 @@
   1.542  
   1.543        if (h->i_timecode < 0) {
   1.544            h->i_timecode = h->i_timecode * -1;
   1.545 -          nuv->time_offset = h->i_timecode;
   1.546 +          nuv->priv->time_diff = h->i_timecode;
   1.547        }
   1.548        else
   1.549 -          h->i_timecode += nuv->time_offset;
   1.550 -      
   1.551 -      GST_BUFFER_TIMESTAMP (buf) = h->i_timecode * GST_MSECOND;
   1.552 -      nuv->last_frame_time = h->i_timecode * GST_MSECOND;
   1.553 +          h->i_timecode += nuv->priv->time_diff;
   1.554 +
   1.555 +      timestamp = h->i_timecode * GST_MSECOND;
   1.556 +
   1.557 +      GST_BUFFER_SIZE (buf) = h->i_length;
   1.558 +      GST_BUFFER_TIMESTAMP (buf) = timestamp;
   1.559 +
   1.560 +      if ((h->i_type == 'V') || (h->i_type == 'A')) {
   1.561 +      }
   1.562    }
   1.563 +  else {
   1.564 +    goto done;
   1.565 +  }
   1.566 +
   1.567  
   1.568    switch (h->i_type) {
   1.569      case 'V':
   1.570      {
   1.571 -      if (h->i_length == 0)
   1.572 -        break;
   1.573 -        
   1.574 -      if (nuv->new_video_segment) {
   1.575 +      pad = nuv->priv->src_video_pad;
   1.576 +
   1.577 +      if (nuv->priv->new_video_segment) {
   1.578          /* send new segment event*/
   1.579 -        gst_pad_push_event (nuv->src_video_pad,
   1.580 -          gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, 
   1.581 +        gst_pad_push_event (nuv->priv->src_video_pad,
   1.582 +          gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0,
   1.583                                       GST_CLOCK_TIME_NONE, 0));
   1.584 -        nuv->new_video_segment = FALSE;
   1.585 +
   1.586 +        if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
   1.587 +            nuv->priv->time_start = timestamp;
   1.588 +        }
   1.589 +        nuv->priv->new_video_segment = FALSE;
   1.590        }
   1.591 -      
   1.592 -      GST_BUFFER_SIZE (buf) = h->i_length;
   1.593 -      gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_video_pad));
   1.594 -      nuv->last_video_return = gst_pad_push (nuv->src_video_pad, buf);
   1.595 -      if (!gst_nuv_combine_flow (nuv)) {
   1.596 -        ret = nuv->last_video_return;
   1.597 -        GST_WARNING_OBJECT (nuv, "error: %d pushing on srcpad %s, is linked? = %d",
   1.598 -            nuv->last_video_return, gst_pad_get_name (nuv->src_video_pad), gst_pad_is_linked (nuv->src_video_pad));
   1.599 -      }
   1.600 +
   1.601        break;
   1.602      }
   1.603      case 'A':
   1.604      {
   1.605 -      if (h->i_length == 0)
   1.606 -        break;
   1.607 -  
   1.608 -      if (nuv->new_audio_segment) {
   1.609 +      pad = nuv->priv->src_audio_pad;
   1.610 +
   1.611 +      if (nuv->priv->new_audio_segment) {
   1.612          /* send new segment event*/
   1.613 -        gst_pad_push_event (nuv->src_audio_pad,
   1.614 -          gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, 
   1.615 +        gst_pad_push_event (nuv->priv->src_audio_pad,
   1.616 +          gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0,
   1.617                                       GST_CLOCK_TIME_NONE, 0));
   1.618 -        nuv->new_audio_segment = FALSE;
   1.619 +
   1.620 +        if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
   1.621 +            nuv->priv->time_start = timestamp;
   1.622 +        }
   1.623 +        nuv->priv->new_audio_segment = FALSE;
   1.624        }
   1.625 -       
   1.626 -      GST_BUFFER_SIZE (buf) = h->i_length;
   1.627 -      gst_buffer_set_caps (buf, GST_PAD_CAPS (nuv->src_audio_pad));
   1.628 -      nuv->last_audio_return = gst_pad_push (nuv->src_audio_pad, buf);
   1.629 -      if (!gst_nuv_combine_flow (nuv)) {
   1.630 -        ret = nuv->last_audio_return;
   1.631 -        GST_WARNING_OBJECT (nuv, "Error %d pushing on srcpad %s, is linked? = %d",
   1.632 -            nuv->last_audio_return, gst_pad_get_name (nuv->src_audio_pad), gst_pad_is_linked (nuv->src_audio_pad));
   1.633 -      }
   1.634 +
   1.635        break;
   1.636      }
   1.637      case 'S':
   1.638      {
   1.639        switch (h->i_compression) {
   1.640          case 'V':
   1.641 -		  if ( !gst_pad_is_linked( nuv->src_video_pad ) )
   1.642 -		    break;
   1.643 -
   1.644            GST_DEBUG_OBJECT (nuv, "sending new video segment: %d", h->i_timecode);
   1.645 -          gst_pad_push_event (nuv->src_video_pad,
   1.646 -              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, h->i_timecode * GST_MSECOND, 
   1.647 +          gst_pad_push_event (nuv->priv->src_video_pad,
   1.648 +              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, h->i_timecode * GST_MSECOND,
   1.649                		GST_CLOCK_TIME_NONE, 0));
   1.650            break;
   1.651 -        case 'A':        
   1.652 -		      if ( !gst_pad_is_linked( nuv->src_audio_pad ) )
   1.653 -		      	break;
   1.654 -
   1.655 +        case 'A':
   1.656            GST_DEBUG_OBJECT (nuv, "sending new audio segment: %d", h->i_timecode);
   1.657 -          gst_pad_push_event (nuv->src_audio_pad,
   1.658 -              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, 
   1.659 +          gst_pad_push_event (nuv->priv->src_audio_pad,
   1.660 +              gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0,
   1.661                		GST_CLOCK_TIME_NONE, 0));
   1.662            break;
   1.663          default:
   1.664 @@ -625,6 +796,8 @@
   1.665        }
   1.666        if (buf != NULL)
   1.667          gst_buffer_unref (buf);
   1.668 +
   1.669 +      goto done;
   1.670      }
   1.671      default:
   1.672        if (buf != NULL)
   1.673 @@ -633,10 +806,37 @@
   1.674        break;
   1.675    }
   1.676  
   1.677 +  if ((buf != NULL) && (pad != NULL)) {
   1.678 +      /* update average time */
   1.679 +      nuv->priv->streamer_offset += h->i_length;
   1.680 +      gst_segment_set_last_stop (&nuv->priv->segment, GST_FORMAT_TIME, timestamp);
   1.681 +      gst_nuv_demux_update_duration (nuv, timestamp);
   1.682 +
   1.683 +      /* pushing the buffer */
   1.684 +      gst_buffer_set_caps (buf, GST_PAD_CAPS (pad));
   1.685 +      ret = gst_pad_push (pad, buf);
   1.686 +
   1.687 +      if (ret != GST_FLOW_OK) {
   1.688 +        if (pad == nuv->priv->src_video_pad) {
   1.689 +            nuv->priv->last_video_return = ret;
   1.690 +        }
   1.691 +        else if (pad == nuv->priv->src_audio_pad) {
   1.692 +            nuv->priv->last_audio_return = ret;
   1.693 +        }
   1.694 +
   1.695 +        /* verify anothers flow if is necessary stop task */
   1.696 +        if (gst_nuv_combine_flow (nuv) != FALSE) {
   1.697 +            ret = GST_FLOW_OK;
   1.698 +        }
   1.699 +
   1.700 +        GST_WARNING_OBJECT (nuv, "error: %d pushing on srcpad %s", ret, gst_pad_get_name (pad));
   1.701 +      }
   1.702 +  }
   1.703 +
   1.704  done:
   1.705 -  nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   1.706 -  g_free (nuv->fh);
   1.707 -  nuv->fh = NULL;
   1.708 +  nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
   1.709 +  g_free (nuv->priv->fh);
   1.710 +  nuv->priv->fh = NULL;
   1.711    return ret;
   1.712  }
   1.713  
   1.714 @@ -646,14 +846,14 @@
   1.715    GstFlowReturn ret = GST_FLOW_OK;
   1.716  
   1.717    /* ffmpeg extra data */
   1.718 -  ret =
   1.719 -      gst_nuv_demux_read_bytes (nuv, nuv->mpeg_data_size, TRUE,
   1.720 -      &nuv->mpeg_buffer);
   1.721 -  if ((ret != GST_FLOW_OK) || (nuv->mpeg_buffer == NULL)) {
   1.722 -    return ret; 
   1.723 +  ret = gst_nuv_demux_read_bytes (nuv, nuv->priv->mpeg_data_size, TRUE,
   1.724 +      &nuv->priv->mpeg_buffer);
   1.725 +  if ((ret != GST_FLOW_OK) || (nuv->priv->mpeg_buffer == NULL)) {
   1.726 +    return ret;
   1.727    }
   1.728 -  GST_BUFFER_SIZE (nuv->mpeg_buffer) = nuv->mpeg_data_size;
   1.729 -  nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   1.730 +
   1.731 +  GST_BUFFER_SIZE (nuv->priv->mpeg_buffer) = nuv->priv->mpeg_data_size;
   1.732 +  nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   1.733    return ret;
   1.734  }
   1.735  
   1.736 @@ -676,13 +876,13 @@
   1.737  
   1.738    if (h->i_length > 0) {
   1.739      if (h->i_compression == 'F') {
   1.740 -      nuv->state = GST_NUV_DEMUX_MPEG_DATA;
   1.741 +      nuv->priv->state = GST_NUV_DEMUX_MPEG_DATA;
   1.742      } else {
   1.743        g_free (h);
   1.744        return GST_FLOW_ERROR;
   1.745      }
   1.746    } else {
   1.747 -    nuv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   1.748 +    nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
   1.749    }
   1.750  
   1.751    g_free (h);
   1.752 @@ -695,12 +895,12 @@
   1.753  {
   1.754    GstFlowReturn ret = GST_FLOW_OK;
   1.755  
   1.756 -  ret = gst_nuv_demux_extended_header_load (nuv, &nuv->eh);
   1.757 +  ret = gst_nuv_demux_extended_header_load (nuv, &nuv->priv->eh);
   1.758    if (ret != GST_FLOW_OK)
   1.759      return ret;
   1.760  
   1.761    gst_nuv_demux_create_pads (nuv);
   1.762 -  nuv->state = GST_NUV_DEMUX_FRAME_HEADER;
   1.763 +  nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
   1.764    return ret;
   1.765  }
   1.766  
   1.767 @@ -733,9 +933,9 @@
   1.768      }
   1.769      g_free (h);
   1.770      h = NULL;
   1.771 -    nuv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
   1.772 +    nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
   1.773    } else {
   1.774 -    nuv->state = GST_NUV_DEMUX_INVALID_DATA;
   1.775 +    nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
   1.776      g_object_unref (buf);
   1.777      GST_ELEMENT_WARNING (nuv, STREAM, FAILED,
   1.778          (_("incomplete NUV support")), ("incomplete NUV support"));
   1.779 @@ -750,13 +950,13 @@
   1.780    GstFlowReturn res = GST_FLOW_OK;
   1.781    GstNuvDemux *nuv = GST_NUV_DEMUX (GST_PAD_PARENT (pad));
   1.782  
   1.783 -  switch (nuv->state) {
   1.784 +  switch (nuv->priv->state) {
   1.785      case GST_NUV_DEMUX_START:
   1.786        res = gst_nuv_demux_stream_file_header (nuv);
   1.787        if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   1.788          goto pause;
   1.789        }
   1.790 -      if (nuv->state != GST_NUV_DEMUX_HEADER_DATA)
   1.791 +      if (nuv->priv->state != GST_NUV_DEMUX_HEADER_DATA)
   1.792          break;
   1.793  
   1.794      case GST_NUV_DEMUX_HEADER_DATA:
   1.795 @@ -764,7 +964,7 @@
   1.796        if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   1.797          goto pause;
   1.798        }
   1.799 -      if (nuv->state != GST_NUV_DEMUX_EXTRA_DATA)
   1.800 +      if (nuv->priv->state != GST_NUV_DEMUX_EXTRA_DATA)
   1.801          break;
   1.802  
   1.803      case GST_NUV_DEMUX_EXTRA_DATA:
   1.804 @@ -772,7 +972,7 @@
   1.805        if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   1.806          goto pause;
   1.807        }
   1.808 -      if (nuv->state != GST_NUV_DEMUX_MPEG_DATA)
   1.809 +      if (nuv->priv->state != GST_NUV_DEMUX_MPEG_DATA)
   1.810          break;
   1.811  
   1.812      case GST_NUV_DEMUX_MPEG_DATA:
   1.813 @@ -781,7 +981,7 @@
   1.814          goto pause;
   1.815        }
   1.816  
   1.817 -      if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER)
   1.818 +      if (nuv->priv->state != GST_NUV_DEMUX_EXTEND_HEADER)
   1.819          break;
   1.820  
   1.821      case GST_NUV_DEMUX_EXTEND_HEADER:
   1.822 @@ -789,7 +989,7 @@
   1.823        if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   1.824          goto pause;
   1.825        }
   1.826 -      if (nuv->state != GST_NUV_DEMUX_EXTEND_HEADER_DATA)
   1.827 +      if (nuv->priv->state != GST_NUV_DEMUX_EXTEND_HEADER_DATA)
   1.828          break;
   1.829  
   1.830      case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
   1.831 @@ -798,7 +998,7 @@
   1.832          goto pause;
   1.833        }
   1.834  
   1.835 -      if (nuv->state != GST_NUV_DEMUX_FRAME_HEADER)
   1.836 +      if (nuv->priv->state != GST_NUV_DEMUX_FRAME_HEADER)
   1.837          break;
   1.838  
   1.839      case GST_NUV_DEMUX_FRAME_HEADER:
   1.840 @@ -806,7 +1006,7 @@
   1.841        if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
   1.842          goto pause;
   1.843        }
   1.844 -      if (nuv->state != GST_NUV_DEMUX_MOVI)
   1.845 +      if (nuv->priv->state != GST_NUV_DEMUX_MOVI)
   1.846          break;
   1.847  
   1.848      case GST_NUV_DEMUX_MOVI:
   1.849 @@ -822,14 +1022,13 @@
   1.850        g_assert_not_reached ();
   1.851    }
   1.852  
   1.853 -  GST_DEBUG_OBJECT (nuv, "state: %d res:%s", nuv->state,
   1.854 -      gst_flow_get_name (res));
   1.855 +  GST_DEBUG_OBJECT (nuv, "state: %d res:%s", nuv->priv->state, gst_flow_get_name (res));
   1.856  
   1.857    return GST_FLOW_OK;
   1.858  
   1.859  pause:
   1.860    GST_LOG_OBJECT (nuv, "pausing task, reason %s", gst_flow_get_name (res));
   1.861 -  gst_pad_pause_task (nuv->sinkpad);
   1.862 +  gst_pad_pause_task (nuv->priv->sinkpad);
   1.863    if (GST_FLOW_IS_FATAL (res)) {
   1.864      GST_ELEMENT_ERROR (nuv, STREAM, FAILED,
   1.865          (_("Internal data stream error.")),
   1.866 @@ -846,12 +1045,12 @@
   1.867    gst_element_post_message (GST_ELEMENT (nuv),
   1.868        gst_message_new_segment_done (GST_OBJECT (nuv), GST_FORMAT_TIME, -1));
   1.869  
   1.870 -  if (nuv->src_video_pad)
   1.871 -    gst_pad_push_event (nuv->src_video_pad, gst_event_new_eos ());
   1.872 -  if (nuv->src_audio_pad)
   1.873 -    gst_pad_push_event (nuv->src_audio_pad, gst_event_new_eos ());
   1.874 +  if (nuv->priv->src_video_pad)
   1.875 +    gst_pad_push_event (nuv->priv->src_video_pad, gst_event_new_eos ());
   1.876 +  if (nuv->priv->src_audio_pad)
   1.877 +    gst_pad_push_event (nuv->priv->src_audio_pad, gst_event_new_eos ());
   1.878  }
   1.879 -    
   1.880 +
   1.881  static GstFlowReturn
   1.882  gst_nuv_demux_read_bytes (GstNuvDemux * nuv, guint64 size, gboolean move,
   1.883      GstBuffer ** buffer)
   1.884 @@ -861,33 +1060,33 @@
   1.885    if (size == 0) {
   1.886      return ret;
   1.887    }
   1.888 -  
   1.889 -  if (nuv->mode == NUV_PULL_MODE) {
   1.890 -    ret = gst_pad_pull_range (nuv->sinkpad, nuv->offset, size, buffer);
   1.891 +
   1.892 +  if (nuv->priv->mode == NUV_PULL_MODE) {
   1.893 +    ret = gst_pad_pull_range (nuv->priv->sinkpad, nuv->priv->offset, size, buffer);
   1.894      if (ret == GST_FLOW_OK) {
   1.895          if (move) {
   1.896 -		    nuv->offset += size;
   1.897 +		    nuv->priv->offset += size;
   1.898  		}
   1.899        /* got eos */
   1.900      } else if (ret == GST_FLOW_UNEXPECTED) {
   1.901        if (buffer != NULL)
   1.902            gst_buffer_unref (buffer);
   1.903 -      
   1.904 +
   1.905        gst_nuv_demux_send_eos (nuv);
   1.906        return GST_FLOW_WRONG_STATE;
   1.907      }
   1.908    } else {
   1.909 -    if (gst_adapter_available (nuv->adapter) < size)
   1.910 +    if (gst_adapter_available (nuv->priv->adapter) < size)
   1.911        return GST_FLOW_ERROR_NO_DATA;
   1.912  
   1.913      if (move) {
   1.914        guint8 *data = NULL;
   1.915 -      data = (guint8 *) gst_adapter_take (nuv->adapter, size);
   1.916 +      data = (guint8 *) gst_adapter_take (nuv->priv->adapter, size);
   1.917        *buffer = gst_buffer_new ();
   1.918        gst_buffer_set_data (*buffer, data, size);
   1.919      } else {
   1.920        guint8 *data = NULL;
   1.921 -      data = (guint8 *) gst_adapter_peek (nuv->adapter, size);
   1.922 +      data = (guint8 *) gst_adapter_peek (nuv->priv->adapter, size);
   1.923        *buffer = gst_buffer_new ();
   1.924        gst_buffer_set_data (*buffer, data, size);
   1.925      }
   1.926 @@ -917,11 +1116,11 @@
   1.927  
   1.928    if (active) {
   1.929      GST_DEBUG_OBJECT (nuv, "activating pull function");
   1.930 -    nuv->mode = NUV_PULL_MODE;
   1.931 -    if (nuv->adapter) {
   1.932 -      gst_adapter_clear (nuv->adapter);
   1.933 -      g_object_unref (nuv->adapter);
   1.934 -      nuv->adapter = NULL;
   1.935 +    nuv->priv->mode = NUV_PULL_MODE;
   1.936 +    if (nuv->priv->adapter) {
   1.937 +      gst_adapter_clear (nuv->priv->adapter);
   1.938 +      g_object_unref (nuv->priv->adapter);
   1.939 +      nuv->priv->adapter = NULL;
   1.940      }
   1.941      gst_pad_start_task (sinkpad, (GstTaskFunction) gst_nuv_demux_loop, sinkpad);
   1.942    } else {
   1.943 @@ -939,11 +1138,11 @@
   1.944    GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
   1.945  
   1.946    if (active) {
   1.947 -    nuv->mode = NUV_PUSH_MODE;
   1.948 -    if (nuv->adapter) {
   1.949 -      gst_adapter_clear (nuv->adapter);
   1.950 +    nuv->priv->mode = NUV_PUSH_MODE;
   1.951 +    if (nuv->priv->adapter) {
   1.952 +      gst_adapter_clear (nuv->priv->adapter);
   1.953      } else {
   1.954 -      nuv->adapter = gst_adapter_new ();
   1.955 +      nuv->priv->adapter = gst_adapter_new ();
   1.956      }
   1.957      GST_DEBUG_OBJECT (nuv, "activating push/chain function");
   1.958    } else {
   1.959 @@ -955,13 +1154,84 @@
   1.960    return TRUE;
   1.961  }
   1.962  
   1.963 +
   1.964 +static gboolean
   1.965 +gst_nuv_demux_sink_event (GstPad *pad, GstEvent *event)
   1.966 +{
   1.967 +  gboolean res;
   1.968 +  GstNuvDemux *nuv;
   1.969 +
   1.970 +  nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
   1.971 +
   1.972 +  switch (GST_EVENT_TYPE (event)) {
   1.973 +    case GST_EVENT_SEEK:
   1.974 +    {
   1.975 +      gdouble rate;
   1.976 +      GstFormat format;
   1.977 +      GstSeekFlags flags;
   1.978 +      GstSeekType cur_type;
   1.979 +      gint64 cur;
   1.980 +      GstSeekType stop_type;
   1.981 +      gint64 stop;
   1.982 +
   1.983 +      gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop);
   1.984 +
   1.985 +      GST_DEBUG_OBJECT (nuv, "got seek, start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, cur, stop);
   1.986 +
   1.987 +      break;
   1.988 +    }
   1.989 +    case GST_EVENT_NEWSEGMENT:
   1.990 +    {
   1.991 +      gint64 start, stop, time;
   1.992 +      gdouble rate, arate;
   1.993 +      GstFormat format;
   1.994 +      gboolean update;
   1.995 +
   1.996 +      GST_DEBUG_OBJECT (nuv, "got a new segment event");
   1.997 +      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
   1.998 +          &start, &stop, &time);
   1.999 +
  1.1000 +      GST_DEBUG_OBJECT (nuv, "got newsegment, start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, start, stop);
  1.1001 +      g_debug ("got newsegment, start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, start, stop);
  1.1002 +      nuv->priv->duration_bytes = stop - start;
  1.1003 +      gst_event_unref (event);
  1.1004 +      res = TRUE;
  1.1005 +      break;
  1.1006 +    }
  1.1007 +    case GST_EVENT_QOS:
  1.1008 +    {
  1.1009 +/*
  1.1010 +      gdouble proportion;
  1.1011 +      GstClockTimeDiff diff;
  1.1012 +      GstClockTime timestamp;
  1.1013 +
  1.1014 +      gst_event_parse_qos (event, &proportion, &diff, &timestamp);
  1.1015 +      if (diff > 0)
  1.1016 +        nuv->time_qos = timecode + diff;
  1.1017 +      else
  1.1018 +        nuv->time_qos = -1;
  1.1019 +*/
  1.1020 +
  1.1021 +      break;
  1.1022 +    }
  1.1023 +
  1.1024 +    case GST_EVENT_EOS:
  1.1025 +    default:
  1.1026 +      res = gst_pad_event_default (pad, event);
  1.1027 +      break;
  1.1028 +  }
  1.1029 +
  1.1030 +  gst_object_unref (nuv);
  1.1031 +  return res;
  1.1032 +}
  1.1033 +
  1.1034  static GstFlowReturn
  1.1035  gst_nuv_demux_chain (GstPad * pad, GstBuffer * buf)
  1.1036  {
  1.1037    GstNuvDemux *nuv = GST_NUV_DEMUX (gst_pad_get_parent (pad));
  1.1038  
  1.1039    GST_DEBUG_OBJECT (nuv, " gst_nuv_demux_chain function");
  1.1040 -  gst_adapter_push (nuv->adapter, buf);
  1.1041 +  gst_adapter_push (nuv->priv->adapter, buf);
  1.1042  
  1.1043    gst_object_unref (nuv);
  1.1044  
  1.1045 @@ -977,40 +1247,46 @@
  1.1046  static void
  1.1047  gst_nuv_demux_reset (GstNuvDemux * nuv)
  1.1048  {
  1.1049 -  nuv->state = GST_NUV_DEMUX_START;
  1.1050 -  nuv->mode = 0;
  1.1051 -  nuv->offset = 0;
  1.1052 -  nuv->time_offset = 0;
  1.1053 +  nuv->priv->state = GST_NUV_DEMUX_START;
  1.1054 +  nuv->priv->mode = 0;
  1.1055 +  nuv->priv->offset = 0;
  1.1056 +  nuv->priv->streamer_offset = 0;
  1.1057 +  nuv->priv->time_start = 0;
  1.1058 +  nuv->priv->time_qos = GST_CLOCK_TIME_NONE;
  1.1059 +  nuv->priv->duration_bytes = GST_CLOCK_TIME_NONE;
  1.1060 +  nuv->priv->duration_time = GST_CLOCK_TIME_NONE;
  1.1061 +  nuv->priv->duration_average = GST_CLOCK_TIME_NONE;
  1.1062 +  gst_segment_init (&nuv->priv->segment, GST_FORMAT_TIME);
  1.1063  
  1.1064 -  if (nuv->adapter != NULL)
  1.1065 -    gst_adapter_clear (nuv->adapter);
  1.1066 +  if (nuv->priv->adapter != NULL)
  1.1067 +    gst_adapter_clear (nuv->priv->adapter);
  1.1068  
  1.1069 -  if (nuv->mpeg_buffer != NULL) {
  1.1070 -    gst_buffer_unref (nuv->mpeg_buffer);
  1.1071 -    nuv->mpeg_buffer = NULL;
  1.1072 +  if (nuv->priv->mpeg_buffer != NULL) {
  1.1073 +    gst_buffer_unref (nuv->priv->mpeg_buffer);
  1.1074 +    nuv->priv->mpeg_buffer = NULL;
  1.1075    }
  1.1076  
  1.1077 -  g_free (nuv->h);
  1.1078 -  nuv->h = NULL;
  1.1079 +  g_free (nuv->priv->h);
  1.1080 +  nuv->priv->h = NULL;
  1.1081  
  1.1082 -  g_free (nuv->eh);
  1.1083 -  nuv->eh = NULL;
  1.1084 +  g_free (nuv->priv->eh);
  1.1085 +  nuv->priv->eh = NULL;
  1.1086  
  1.1087 -  g_free (nuv->fh);
  1.1088 -  nuv->fh = NULL;
  1.1089 +  g_free (nuv->priv->fh);
  1.1090 +  nuv->priv->fh = NULL;
  1.1091  }
  1.1092  
  1.1093  static void
  1.1094  gst_nuv_demux_destoy_src_pad (GstNuvDemux * nuv)
  1.1095  {
  1.1096 -  if (nuv->src_video_pad) {
  1.1097 -    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_video_pad);
  1.1098 -    nuv->src_video_pad = NULL;
  1.1099 +  if (nuv->priv->src_video_pad) {
  1.1100 +    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->priv->src_video_pad);
  1.1101 +    nuv->priv->src_video_pad = NULL;
  1.1102    }
  1.1103  
  1.1104 -  if (nuv->src_audio_pad) {
  1.1105 -    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->src_audio_pad);
  1.1106 -    nuv->src_audio_pad = NULL;
  1.1107 +  if (nuv->priv->src_audio_pad) {
  1.1108 +    gst_element_remove_pad (GST_ELEMENT (nuv), nuv->priv->src_audio_pad);
  1.1109 +    nuv->priv->src_audio_pad = NULL;
  1.1110    }
  1.1111  }
  1.1112  
  1.1113 @@ -1021,6 +1297,7 @@
  1.1114  
  1.1115    switch (transition) {
  1.1116      case GST_STATE_CHANGE_READY_TO_PAUSED:
  1.1117 +      gst_nuv_demux_reset (GST_NUV_DEMUX (element));
  1.1118        break;
  1.1119      default:
  1.1120        break;
  1.1121 @@ -1031,10 +1308,9 @@
  1.1122      goto done;
  1.1123  
  1.1124    switch (transition) {
  1.1125 -    case GST_STATE_CHANGE_PAUSED_TO_READY:
  1.1126 -      GST_DEBUG_OBJECT (element, "GST_STATE_CHANGE_PAUSED_TO_READY");
  1.1127 +    case GST_STATE_CHANGE_READY_TO_NULL:
  1.1128 +      gst_nuv_demux_reset (GST_NUV_DEMUX (element));
  1.1129        gst_nuv_demux_destoy_src_pad (GST_NUV_DEMUX (element));
  1.1130 -      gst_nuv_demux_reset (GST_NUV_DEMUX (element));
  1.1131        break;
  1.1132      default:
  1.1133        break;
  1.1134 @@ -1044,6 +1320,70 @@
  1.1135    return ret;
  1.1136  }
  1.1137  
  1.1138 +static void
  1.1139 +gst_nuv_demux_update_duration (GstNuvDemux *nuv, guint64 current_timestamp)
  1.1140 +{
  1.1141 +    guint64 interval = 0;
  1.1142 +
  1.1143 +    if (gst_nuv_demux_get_time_duration (nuv) != GST_CLOCK_TIME_NONE)
  1.1144 +        return;
  1.1145 +
  1.1146 +    interval  = current_timestamp - nuv->priv->last_update;
  1.1147 +
  1.1148 +    if (interval > (10 * GST_SECOND)) {
  1.1149 +        GstMessage* msg = NULL;
  1.1150 +        gint64 average = 0;
  1.1151 +        gint64 duration_bytes = gst_nuv_demux_get_bytes_duration (nuv);
  1.1152 +
  1.1153 +        if (duration_bytes == GST_CLOCK_TIME_NONE)
  1.1154 +            return;
  1.1155 +
  1.1156 +        interval = gst_util_uint64_scale (1, current_timestamp - nuv->priv->time_start, GST_SECOND);
  1.1157 +        average = gst_util_uint64_scale (1 , nuv->priv->streamer_offset, interval);
  1.1158 +        nuv->priv->duration_average = gst_util_uint64_scale (GST_SECOND, duration_bytes, average);
  1.1159 +        nuv->priv->last_update = current_timestamp;
  1.1160 +        msg = gst_message_new_duration (GST_OBJECT (nuv), GST_FORMAT_TIME, nuv->priv->duration_average);
  1.1161 +        gst_element_post_message (GST_ELEMENT (nuv), msg);
  1.1162 +        GST_DEBUG_OBJECT (nuv, "New Duration Average %"G_GUINT64_FORMAT, nuv->priv->duration_average);
  1.1163 +    }
  1.1164 +}
  1.1165 +
  1.1166 +static gint64
  1.1167 +gst_nuv_demux_get_bytes_duration (GstNuvDemux *nuv)
  1.1168 +{
  1.1169 +    if (nuv->priv->duration_bytes == GST_CLOCK_TIME_NONE) {
  1.1170 +        GstPad *peer = gst_pad_get_peer (nuv->priv->sinkpad);
  1.1171 +        GstQuery *query = gst_query_new_duration (GST_FORMAT_BYTES);
  1.1172 +        if (gst_pad_query (peer, query)) {
  1.1173 +            gint64 duration;
  1.1174 +
  1.1175 +            gst_query_parse_duration (query, NULL, &duration);
  1.1176 +            nuv->priv->duration_bytes = duration;
  1.1177 +        }
  1.1178 +        gst_object_unref (peer);
  1.1179 +        gst_query_unref (query);
  1.1180 +    }
  1.1181 +    return nuv->priv->duration_bytes;
  1.1182 +}
  1.1183 +
  1.1184 +static gint64
  1.1185 +gst_nuv_demux_get_time_duration (GstNuvDemux *nuv)
  1.1186 +{
  1.1187 +    if (nuv->priv->duration_time == GST_CLOCK_TIME_NONE) {
  1.1188 +        GstPad *peer = gst_pad_get_peer (nuv->priv->sinkpad);
  1.1189 +        GstQuery *query = gst_query_new_duration (GST_FORMAT_TIME);
  1.1190 +        if (gst_pad_query (peer, query)) {
  1.1191 +            gint64 duration;
  1.1192 +            gst_query_parse_duration (query, NULL, &duration);
  1.1193 +            nuv->priv->duration_time = duration;
  1.1194 +        }
  1.1195 +        gst_object_unref (peer);
  1.1196 +        gst_query_unref (query);
  1.1197 +    }
  1.1198 +    return nuv->priv->duration_time;
  1.1199 +}
  1.1200 +
  1.1201 +
  1.1202  static gboolean
  1.1203  plugin_init (GstPlugin * plugin)
  1.1204  {
     2.1 --- a/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.h	Fri Nov 17 13:09:12 2006 +0000
     2.2 +++ b/gst-plugins-nuvdemux/nuvdemux/gstnuvdemux.h	Fri Nov 17 13:18:48 2006 +0000
     2.3 @@ -38,155 +38,10 @@
     2.4  #define GST_IS_NUV_DEMUX_CLASS(klass) \
     2.5    (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_NUV_DEMUX))
     2.6  
     2.7 -#define DEMUX_INDEX_SIZE_MAX (100000)
     2.8 -
     2.9 -/* Indexes (timecodes/offsets) conversion structures */
    2.10 -typedef struct
    2.11 -{
    2.12 -    gint64 i_time;
    2.13 -    gint64 i_offset;
    2.14 -
    2.15 -} nuv_demux_index_entry;
    2.16 -
    2.17 -typedef struct
    2.18 -{
    2.19 -    gint i_idx;
    2.20 -    gint i_idx_max;
    2.21 -
    2.22 -    nuv_demux_index_entry idx[DEMUX_INDEX_SIZE_MAX];
    2.23 -} nuv_demux_index;
    2.24 -
    2.25 -/* */
    2.26 -typedef struct
    2.27 -{
    2.28 -    gchar id[12];       /* "NuppelVideo\0" or "MythTVVideo\0" */
    2.29 -    gchar version[5];    /* "x.xx\0" */
    2.30 -
    2.31 -    gint  i_width;
    2.32 -    gint  i_height;
    2.33 -    gint  i_width_desired;
    2.34 -    gint  i_height_desired;
    2.35 -
    2.36 -    gchar i_mode;            /* P progressive, I interlaced */
    2.37 -
    2.38 -    gdouble  d_aspect;       /* 1.0 squared pixel */
    2.39 -    gdouble  d_fps;
    2.40 -    //fps num/denom
    2.41 -    gint     i_fpsn;
    2.42 -    gint     i_fpsd;
    2.43 -
    2.44 -    gint     i_video_blocks; /* 0 no video, -1 unknown */
    2.45 -    gint     i_audio_blocks;
    2.46 -    gint     i_text_blocks;
    2.47 -
    2.48 -    gint     i_keyframe_distance;
    2.49 -
    2.50 -} nuv_header;
    2.51 -
    2.52 -typedef struct
    2.53 -{
    2.54 -    gchar i_type;        /* A: audio, V: video, S: sync; T: test
    2.55 -                           R: Seekpoint (string:RTjjjjjjjj)
    2.56 -                           D: Extra data for codec */
    2.57 -    gchar i_compression; /* V: 0 uncompressed
    2.58 -                              1 RTJpeg
    2.59 -                              2 RTJpeg+lzo
    2.60 -                              N black frame
    2.61 -                              L copy last
    2.62 -                           A: 0 uncompressed (44100 1-bits, 2ch)
    2.63 -                              1 lzo
    2.64 -                              2 layer 2
    2.65 -                              3 layer 3
    2.66 -                              F flac
    2.67 -                              S shorten
    2.68 -                              N null frame loudless
    2.69 -                              L copy last
    2.70 -                            S: B audio and vdeo sync point
    2.71 -                               A audio sync info (timecode == effective
    2.72 -                                    dsp frequency*100)
    2.73 -                               V next video sync (timecode == next video
    2.74 -                                    frame num)
    2.75 -                               S audio,video,text correlation */
    2.76 -    gchar i_keyframe;    /* 0 keyframe, else no no key frame */
    2.77 -    guint8 i_filters;  /* 0x01: gauss 5 pixel (8,2,2,2,2)/16
    2.78 -                           0x02: gauss 5 pixel (8,1,1,1,1)/12
    2.79 -                           0x04: cartoon filter */
    2.80 -
    2.81 -    gint32 i_timecode;     /* ms */
    2.82 -
    2.83 -    gint i_length;       /* V,A,T: length of following data
    2.84 -                           S: length of packet correl */
    2.85 -} nuv_frame_header;
    2.86 -
    2.87 -/* FIXME Not sure of this one */
    2.88 -typedef struct
    2.89 -{
    2.90 -    gint             i_version;
    2.91 -    guint32		     i_video_fcc;
    2.92 -
    2.93 -    guint32		     i_audio_fcc;
    2.94 -    gint             i_audio_sample_rate;
    2.95 -    gint             i_audio_bits_per_sample;
    2.96 -    gint             i_audio_channels;
    2.97 -    gint             i_audio_compression_ratio;
    2.98 -    gint             i_audio_quality;
    2.99 -    gint             i_rtjpeg_quality;
   2.100 -    gint             i_rtjpeg_luma_filter;
   2.101 -    gint             i_rtjpeg_chroma_filter;
   2.102 -    gint             i_lavc_bitrate;
   2.103 -    gint             i_lavc_qmin;
   2.104 -    gint             i_lavc_qmax;
   2.105 -    gint             i_lavc_maxqdiff;
   2.106 -    gint64         	 i_seekable_offset;
   2.107 -    gint64           i_keyframe_adjust_offset;
   2.108 -
   2.109 -} nuv_extended_header;
   2.110 -
   2.111 -typedef enum {
   2.112 -  GST_NUV_DEMUX_START,
   2.113 -  GST_NUV_DEMUX_HEADER_DATA,
   2.114 -  GST_NUV_DEMUX_EXTRA_DATA,
   2.115 -  GST_NUV_DEMUX_MPEG_DATA,
   2.116 -  GST_NUV_DEMUX_EXTEND_HEADER,
   2.117 -  GST_NUV_DEMUX_EXTEND_HEADER_DATA,
   2.118 -  GST_NUV_DEMUX_FRAME_HEADER,
   2.119 -  GST_NUV_DEMUX_MOVI,
   2.120 -  GST_NUV_DEMUX_INVALID_DATA
   2.121 -} GstNuvDemuxState;
   2.122 -
   2.123 +typedef struct _GstNuvDemuxPrivate GstNuvDemuxPrivate;
   2.124  typedef struct _GstNuvDemux {
   2.125 -  GstElement     parent;
   2.126 -
   2.127 -  guint         mode;
   2.128 -  GstAdapter    *adapter; 
   2.129 -
   2.130 -  /* pads */
   2.131 -  GstPad        *sinkpad;
   2.132 -  GstPad        *src_video_pad;  
   2.133 -  GstPad        *src_audio_pad;
   2.134 -
   2.135 -  GstFlowReturn last_video_return;
   2.136 -  GstFlowReturn last_audio_return;
   2.137 -
   2.138 -  /* NUV decoding state */
   2.139 -  GstNuvDemuxState  state;
   2.140 -  guint64           duration;
   2.141 -  guint64           offset;
   2.142 -  guint64           time_offset;
   2.143 -  guint64           last_frame_time;
   2.144 -  gboolean          new_audio_segment;
   2.145 -  gboolean          new_video_segment;
   2.146 -
   2.147 -  /* Mpeg ExtraData */
   2.148 -  guint64       mpeg_data_size;
   2.149 -  GstBuffer     *mpeg_buffer;
   2.150 -  
   2.151 -  nuv_header *h;
   2.152 -  nuv_extended_header *eh;
   2.153 -  nuv_frame_header *fh;
   2.154 -  
   2.155 -  /* FIXME: change these fields to private struct */
   2.156 -  /* first data buffer received, should sent new_segment */
   2.157 +  GstElement          parent;
   2.158 +  GstNuvDemuxPrivate *priv;
   2.159  } GstNuvDemux;
   2.160  
   2.161  typedef struct _GstNuvDemuxClass {