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