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