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