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