renatofilho@754: /*
renatofilho@754:  * GStreamer Copyright (C) <2006> Renato Araujo Oliveira Filho
renatofilho@754:  * <renato.filho@indt.org.br> Rosfran Borges <rosfran.borges@indt.org.br>
renatofilho@754:  * This library is free software; you can redistribute it and/or modify it
renatofilho@754:  * under the terms of the GNU Library General Public License as published
renatofilho@754:  * by the Free Software Foundation; either version 2 of the License, or (at 
renatofilho@754:  * your option) any later version. This library is distributed in the hope 
renatofilho@754:  * that it will be useful, but WITHOUT ANY WARRANTY; without even the
renatofilho@754:  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
renatofilho@754:  * See the GNU Library General Public License for more details. You should 
renatofilho@754:  * have received a copy of the GNU Library General Public License along
renatofilho@754:  * with this library; if not, write to the Free Software Foundation, Inc.,
renatofilho@754:  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
renatofilho@608:  */
renatofilho@754: /*
renatofilho@754:  * Element-Checklist-Version: 5 
renatofilho@754:  */
renatofilho@608: 
renatofilho@608: /**
renatofilho@608:  * SECTION:element-nuvdemux
renatofilho@608:  *
renatofilho@608:  * <refsect2>
renatofilho@608:  * <para>
renatofilho@608:  * Demuxes an .nuv file into raw or compressed audio and/or video streams.
renatofilho@608:  * </para>
renatofilho@608:  * <para>
renatofilho@608:  * This element currently only supports pull-based scheduling.
renatofilho@608:  * </para>
renatofilho@608:  * <title>Example launch line</title>
renatofilho@608:  * <para>
renatofilho@608:  * <programlisting>
renatofilho@608:  * 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:  * </programlisting>
renatofilho@608:  * Play (parse and decode) an .nuv file and try to output it to
renatofilho@608:  * an automatically detected soundcard and videosink. If the NUV file contains
renatofilho@608:  * compressed audio or video data, this will only work if you have the
renatofilho@608:  * right decoder elements/plugins installed.
renatofilho@608:  * </para>
renatofilho@608:  * </refsect2>
renatofilho@608:  *
renatofilho@608:  */
renatofilho@608: 
renatofilho@608: #ifdef HAVE_CONFIG_H
renatofilho@608: #include "config.h"
renatofilho@608: #endif
renatofilho@608: 
renatofilho@608: #include <gst/gst.h>
renatofilho@608: #include <gst/gsterror.h>
renatofilho@608: #include <gst/gstplugin.h>
renatofilho@608: #include <string.h>
renatofilho@608: #include <math.h>
renatofilho@608: 
renatofilho@608: #include "glib/gi18n.h"
renatofilho@608: #include "gstnuvdemux.h"
renatofilho@608: 
renatofilho@608: #define GST_NUV_DEMUX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_NUV_DEMUX, GstNuvDemuxPrivate))
renatofilho@608: 
renatofilho@751: GST_DEBUG_CATEGORY_STATIC(nuvdemux_debug);
renatofilho@608: #define GST_CAT_DEFAULT nuvdemux_debug
renatofilho@608: #define GST_FLOW_ERROR_NO_DATA  -101
renatofilho@608: #define GST_FLOW_ERROR_EOS	-102
renatofilho@608: 
renatofilho@754: enum {
renatofilho@754:     NUV_PUSH_MODE = 0,
renatofilho@754:     NUV_PULL_MODE
renatofilho@608: };
renatofilho@608: 
renatofilho@751: GST_DEBUG_CATEGORY_EXTERN(GST_CAT_EVENT);
renatofilho@608: 
renatofilho@608: static const GstElementDetails gst_nuv_demux_details =
renatofilho@751: GST_ELEMENT_DETAILS("Nuv demuxer",
renatofilho@754:                     "Codec/Demuxer",
renatofilho@754:                     "Demultiplex a .nuv file into audio and video",
renatofilho@754:                     "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>,"
renatofilho@754:                     "Rosfran Borges <rosfran.borges@indt.org.br>");
renatofilho@608: 
renatofilho@608: 
renatofilho@754: /*
renatofilho@754:  * file header 
renatofilho@754:  */
renatofilho@754: typedef struct {
renatofilho@754:     gchar           id[12];     /* "NuppelVideo\0" or "MythTVVideo\0" */
renatofilho@754:     gchar           version[5]; /* "x.xx\0" */
renatofilho@608: 
renatofilho@754:     gint            i_width;
renatofilho@754:     gint            i_height;
renatofilho@754:     gint            i_width_desired;
renatofilho@754:     gint            i_height_desired;
renatofilho@608: 
renatofilho@754:     gchar           i_mode;     /* P progressive, I interlaced */
renatofilho@608: 
renatofilho@754:     gdouble         d_aspect;   /* 1.0 squared pixel */
renatofilho@754:     gdouble         d_fps;
renatofilho@754:     // fps num/denom
renatofilho@754:     gint            i_fpsn;
renatofilho@754:     gint            i_fpsd;
renatofilho@608: 
renatofilho@754:     gint            i_video_blocks; /* 0 no video, -1 unknown */
renatofilho@754:     gint            i_audio_blocks;
renatofilho@754:     gint            i_text_blocks;
renatofilho@608: 
renatofilho@754:     gint            i_keyframe_distance;
renatofilho@608: 
renatofilho@608: } nuv_header;
renatofilho@608: 
renatofilho@754: /*
renatofilho@754:  * frame header 
renatofilho@754:  */
renatofilho@754: typedef struct {
renatofilho@754:     gchar           i_type;     /* A: audio, V: video, S: sync; T: test R: 
renatofilho@754:                                  * Seekpoint (string:RTjjjjjjjj) D: Extra
renatofilho@754:                                  * data for codec */
renatofilho@754:     gchar           i_compression;  /* V: 0 uncompressed 1 RTJpeg 2
renatofilho@754:                                      * RTJpeg+lzo N black frame L copy
renatofilho@754:                                      * last A: 0 uncompressed (44100
renatofilho@754:                                      * 1-bits, 2ch) 1 lzo 2 layer 2 3
renatofilho@754:                                      * layer 3 F flac S shorten N null
renatofilho@754:                                      * frame loudless L copy last S: B
renatofilho@754:                                      * audio and vdeo sync point A audio
renatofilho@754:                                      * sync info (timecode == effective
renatofilho@754:                                      * dsp frequency*100) V next video
renatofilho@754:                                      * sync (timecode == next video frame
renatofilho@754:                                      * num) S audio,video,text correlation 
renatofilho@754:                                      */
renatofilho@754:     gchar           i_keyframe; /* 0 keyframe, else no no key frame */
renatofilho@754:     guint8          i_filters;  /* 0x01: gauss 5 pixel (8,2,2,2,2)/16
renatofilho@754:                                  * 0x02: gauss 5 pixel (8,1,1,1,1)/12
renatofilho@754:                                  * 0x04: cartoon filter */
renatofilho@608: 
renatofilho@754:     gint32          i_timecode; /* ms */
renatofilho@608: 
renatofilho@754:     gint            i_length;   /* V,A,T: length of following data S:
renatofilho@754:                                  * length of packet correl */
renatofilho@608: } nuv_frame_header;
renatofilho@608: 
renatofilho@608: 
renatofilho@754: /*
renatofilho@754:  * FIXME Not sure of this one 
renatofilho@754:  */
renatofilho@754: typedef struct {
renatofilho@754:     gint            i_version;
renatofilho@754:     guint32         i_video_fcc;
renatofilho@608: 
renatofilho@754:     guint32         i_audio_fcc;
renatofilho@754:     gint            i_audio_sample_rate;
renatofilho@754:     gint            i_audio_bits_per_sample;
renatofilho@754:     gint            i_audio_channels;
renatofilho@754:     gint            i_audio_compression_ratio;
renatofilho@754:     gint            i_audio_quality;
renatofilho@754:     gint            i_rtjpeg_quality;
renatofilho@754:     gint            i_rtjpeg_luma_filter;
renatofilho@754:     gint            i_rtjpeg_chroma_filter;
renatofilho@754:     gint            i_lavc_bitrate;
renatofilho@754:     gint            i_lavc_qmin;
renatofilho@754:     gint            i_lavc_qmax;
renatofilho@754:     gint            i_lavc_maxqdiff;
renatofilho@754:     gint64          i_seekable_offset;
renatofilho@754:     gint64          i_keyframe_adjust_offset;
renatofilho@608: 
renatofilho@608: } nuv_extended_header;
renatofilho@608: 
renatofilho@754: typedef struct {
renatofilho@754:     gint64          timecode;
renatofilho@754:     gint64          offset;
renatofilho@608: 
renatofilho@608: } frame_index_data;
renatofilho@608: 
renatofilho@754: typedef enum {
renatofilho@754:     GST_NUV_DEMUX_START,
renatofilho@754:     GST_NUV_DEMUX_HEADER_DATA,
renatofilho@754:     GST_NUV_DEMUX_EXTRA_DATA,
renatofilho@754:     GST_NUV_DEMUX_MPEG_DATA,
renatofilho@754:     GST_NUV_DEMUX_EXTEND_HEADER,
renatofilho@754:     GST_NUV_DEMUX_EXTEND_HEADER_DATA,
renatofilho@754:     GST_NUV_DEMUX_INDEX_CREATE,
renatofilho@754:     GST_NUV_DEMUX_FRAME_HEADER,
renatofilho@754:     GST_NUV_DEMUX_MOVI,
renatofilho@754:     GST_NUV_DEMUX_INVALID_DATA
renatofilho@608: } GstNuvDemuxState;
renatofilho@608: 
renatofilho@754: struct _GstNuvDemuxPrivate {
renatofilho@754:     /*
renatofilho@754:      * used for indicate the mode 
renatofilho@754:      */
renatofilho@754:     guint           mode;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * used on push mode 
renatofilho@754:      */
renatofilho@754:     GstAdapter     *adapter;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * pads 
renatofilho@754:      */
renatofilho@754:     GstPad         *sinkpad;
renatofilho@754:     GstPad         *src_video_pad;
renatofilho@754:     GstPad         *src_audio_pad;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * Flow control 
renatofilho@754:      */
renatofilho@754:     GstFlowReturn   last_video_return;
renatofilho@754:     GstFlowReturn   last_audio_return;
renatofilho@754:     gboolean        more_data;
renatofilho@754:     gboolean        eos;
renatofilho@754:     gboolean        new_file;
renatofilho@754:     guint           segment;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * NUV decoding state 
renatofilho@754:      */
renatofilho@754:     GstNuvDemuxState state;
renatofilho@754:     guint64         offset;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * duration information 
renatofilho@754:      */
renatofilho@754:     guint64         duration_bytes;
renatofilho@754:     guint64         duration_time;
renatofilho@754:     guint64         segment_stop;
renatofilho@754:     guint64         segment_start;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * segment control info 
renatofilho@754:      */
renatofilho@754:     gboolean        new_audio_segment;
renatofilho@754:     gboolean        new_video_segment;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * Mpeg ExtraData 
renatofilho@754:      */
renatofilho@754:     guint64         mpeg_data_size;
renatofilho@754:     GstBuffer      *mpeg_buffer;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * Headers 
renatofilho@754:      */
renatofilho@754:     nuv_header      h;
renatofilho@754:     nuv_extended_header eh;
renatofilho@754:     nuv_frame_header fh;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * anothers info 
renatofilho@754:      */
renatofilho@754:     guint64         header_lengh;
renatofilho@754:     gint64          time_start;
renatofilho@754:     gint64          time_diff;
renatofilho@754:     gint64          time_qos;
renatofilho@754:     guint64         last_frame_time;
renatofilho@754:     GSList         *index;
renatofilho@608: };
renatofilho@608: 
renatofilho@608: 
renatofilho@751: static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE("sink",
renatofilho@754:                                                                     GST_PAD_SINK,
renatofilho@754:                                                                     GST_PAD_ALWAYS,
renatofilho@754:                                                                     GST_STATIC_CAPS
renatofilho@754:                                                                     ("video/x-nuv"));
renatofilho@608: 
renatofilho@608: static GstStaticPadTemplate audio_src_template =
renatofilho@751: GST_STATIC_PAD_TEMPLATE("audio_src",
renatofilho@754:                         GST_PAD_SRC,
renatofilho@754:                         GST_PAD_SOMETIMES,
renatofilho@754:                         GST_STATIC_CAPS_ANY);
renatofilho@608: 
renatofilho@608: static GstStaticPadTemplate video_src_template =
renatofilho@751: GST_STATIC_PAD_TEMPLATE("video_src",
renatofilho@754:                         GST_PAD_SRC,
renatofilho@754:                         GST_PAD_SOMETIMES,
renatofilho@754:                         GST_STATIC_CAPS_ANY);
renatofilho@608: 
renatofilho@754: static void     gst_nuv_demux_dispose(GObject * object);
renatofilho@754: static void     gst_nuv_demux_finalize(GObject * object);
renatofilho@754: static GstStateChangeReturn gst_nuv_demux_change_state(GstElement *
renatofilho@754:                                                        element,
renatofilho@754:                                                        GstStateChange
renatofilho@754:                                                        transition);
renatofilho@754: static void     gst_nuv_demux_loop(GstPad * pad);
renatofilho@751: static GstFlowReturn gst_nuv_demux_chain(GstPad * pad, GstBuffer * buf);
renatofilho@751: static GstFlowReturn gst_nuv_demux_play(GstPad * pad);
renatofilho@751: static gboolean gst_nuv_demux_sink_activate_pull(GstPad * sinkpad,
renatofilho@754:                                                  gboolean active);
renatofilho@751: static gboolean gst_nuv_demux_sink_activate_push(GstPad * pad,
renatofilho@754:                                                  gboolean active);
renatofilho@751: static gboolean gst_nuv_demux_sink_activate(GstPad * sinkpad);
renatofilho@751: static gboolean gst_nuv_demux_sink_event(GstPad * pad, GstEvent * event);
renatofilho@751: static gboolean gst_nuv_demux_srcpad_event(GstPad * pad, GstEvent * event);
renatofilho@751: static frame_index_data *gst_nuv_demux_do_seek_index(GstNuvDemux * nuv,
renatofilho@754:                                                      gint64 seek_pos,
renatofilho@754:                                                      gint64 segment_stop,
renatofilho@754:                                                      GstFormat format);
renatofilho@608: 
renatofilho@608: 
renatofilho@751: static GstFlowReturn gst_nuv_demux_move_bytes(GstNuvDemux * nuv,
renatofilho@754:                                               guint64 size);
renatofilho@754: static GstFlowReturn gst_nuv_demux_read_bytes(GstNuvDemux * nuv,
renatofilho@754:                                               guint64 size, gboolean move,
renatofilho@754:                                               GstBuffer ** buffer);
renatofilho@754: static void     gst_nuv_demux_reset(GstNuvDemux * nuv);
renatofilho@754: static void     gst_nuv_demux_destoy_src_pad(GstNuvDemux * nuv);
renatofilho@754: static void     gst_nuv_demux_send_eos(GstNuvDemux * nuv);
renatofilho@754: static void     gst_nuv_demux_create_seek_index(GstNuvDemux * nuv);
renatofilho@608: 
renatofilho@608: 
renatofilho@751: #if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
renatofilho@754: GstBuffer      *gst_adapter_take_buffer(GstAdapter * adapter,
renatofilho@754:                                         guint nbytes);
renatofilho@608: #endif
renatofilho@608: 
renatofilho@608: 
renatofilho@751: GST_BOILERPLATE(GstNuvDemux, gst_nuv_demux, GstElement, GST_TYPE_ELEMENT);
renatofilho@608: 
renatofilho@608: /******************************************************************************
renatofilho@608:  * Utils function
renatofilho@608:  ******************************************************************************/
renatofilho@608: #if G_BYTE_ORDER == G_BIG_ENDIAN
renatofilho@754: static inline   gdouble
renatofilho@751: _gdouble_swap_le_be(gdouble * d)
renatofilho@608: {
renatofilho@754:     union {
renatofilho@754:         guint64         i;
renatofilho@754:         gdouble         d;
renatofilho@754:     } u;
renatofilho@608: 
renatofilho@754:     u.d = *d;
renatofilho@754:     u.i = GUINT64_SWAP_LE_BE(u.i);
renatofilho@754:     return u.d;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: #define READ_DOUBLE_FROM_LE(d) (_gdouble_swap_le_be((gdouble* ) d))
renatofilho@754: #else                           /* G_BYTE_ORDER != G_BIG_ENDIAN */
renatofilho@608: #define READ_DOUBLE_FROM_LE(d) *((gdouble* ) (d))
renatofilho@754: #endif                          /* G_BYTE_ORDER != G_BIG_ENDIAN */
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: double2fraction(double in, int *num, int *denom)
renatofilho@608: {
renatofilho@754:     if (in == 29.97) {
renatofilho@754:         *num = 30000;
renatofilho@754:         *denom = 1001;
renatofilho@754:     } else if (in == 23.976) {
renatofilho@754:         *num = 24000;
renatofilho@754:         *denom = 1001;
renatofilho@754:     } else {
renatofilho@754:         *denom = 1;
renatofilho@754:         while (in - floor(in) >= 0.1) {
renatofilho@754:             *denom *= 10;
renatofilho@754:             in *= 10.0;
renatofilho@754:         }
renatofilho@754:         *num = (int) floor(in);
renatofilho@754:     }
renatofilho@608: }
renatofilho@608: 
renatofilho@754: /*
renatofilho@754:  * GObject Functions 
renatofilho@754:  */
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_base_init(gpointer klass)
renatofilho@608: {
renatofilho@754:     GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
renatofilho@608: 
renatofilho@754:     gst_element_class_add_pad_template(element_class,
renatofilho@754:                                        gst_static_pad_template_get
renatofilho@754:                                        (&audio_src_template));
renatofilho@608: 
renatofilho@754:     gst_element_class_add_pad_template(element_class,
renatofilho@754:                                        gst_static_pad_template_get
renatofilho@754:                                        (&video_src_template));
renatofilho@608: 
renatofilho@754:     gst_element_class_add_pad_template(element_class,
renatofilho@754:                                        gst_static_pad_template_get
renatofilho@754:                                        (&sink_template));
renatofilho@754:     gst_element_class_set_details(element_class, &gst_nuv_demux_details);
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_class_init(GstNuvDemuxClass * klass)
renatofilho@608: {
renatofilho@754:     GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass);
renatofilho@754:     GObjectClass   *gobject_class = (GObjectClass *) klass;
renatofilho@608: 
renatofilho@754:     GST_DEBUG_CATEGORY_INIT(nuvdemux_debug, "nuvdemux",
renatofilho@754:                             0, "Demuxer for NUV streams");
renatofilho@608: 
renatofilho@754:     parent_class = g_type_class_peek_parent(klass);
renatofilho@608: 
renatofilho@754:     gobject_class->dispose = gst_nuv_demux_dispose;
renatofilho@754:     gobject_class->finalize = gst_nuv_demux_finalize;
renatofilho@754:     gstelement_class->change_state = gst_nuv_demux_change_state;
renatofilho@608: 
renatofilho@754:     g_type_class_add_private(gobject_class, sizeof(GstNuvDemuxPrivate));
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_init(GstNuvDemux * nuv, GstNuvDemuxClass * nuv_class)
renatofilho@608: {
renatofilho@754:     nuv->priv = GST_NUV_DEMUX_GET_PRIVATE(nuv);
renatofilho@754:     nuv->priv->sinkpad =
renatofilho@754:         gst_pad_new_from_static_template(&sink_template, "sink");
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * creating adapter 
renatofilho@754:      */
renatofilho@754:     nuv->priv->mode = NUV_PUSH_MODE;
renatofilho@754:     nuv->priv->adapter = gst_adapter_new();
renatofilho@608: 
renatofilho@754:     nuv->priv->new_audio_segment = TRUE;
renatofilho@754:     nuv->priv->new_video_segment = TRUE;
renatofilho@608: 
renatofilho@754:     gst_pad_set_activate_function(nuv->priv->sinkpad,
renatofilho@754:                                   gst_nuv_demux_sink_activate);
renatofilho@754:     gst_pad_set_activatepull_function(nuv->priv->sinkpad,
renatofilho@754:                                       gst_nuv_demux_sink_activate_pull);
renatofilho@754:     gst_pad_set_activatepush_function(nuv->priv->sinkpad,
renatofilho@754:                                       gst_nuv_demux_sink_activate_push);
renatofilho@754:     gst_pad_set_chain_function(nuv->priv->sinkpad,
renatofilho@754:                                GST_DEBUG_FUNCPTR(gst_nuv_demux_chain));
renatofilho@754:     gst_pad_set_event_function(nuv->priv->sinkpad,
renatofilho@754:                                GST_DEBUG_FUNCPTR
renatofilho@754:                                (gst_nuv_demux_sink_event));
renatofilho@714: 
renatofilho@608: 
renatofilho@754:     gst_element_add_pad(GST_ELEMENT(nuv), nuv->priv->sinkpad);
renatofilho@608: 
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_dispose(GObject * object)
renatofilho@608: {
renatofilho@754:     GstNuvDemux    *nuv = GST_NUV_DEMUX(object);
renatofilho@608: 
renatofilho@608: 
renatofilho@754:     if (nuv->priv->mpeg_buffer != NULL) {
renatofilho@754:         gst_buffer_unref(nuv->priv->mpeg_buffer);
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     gst_nuv_demux_reset(GST_NUV_DEMUX(object));
renatofilho@754:     gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(object));
renatofilho@608: 
renatofilho@754:     if (nuv->priv->adapter != NULL) {
renatofilho@754:         gst_object_unref(nuv->priv->adapter);
renatofilho@754:     }
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_finalize(GObject * object)
renatofilho@608: {
renatofilho@754:     G_OBJECT_CLASS(parent_class)->finalize(object);
renatofilho@608: }
renatofilho@608: 
renatofilho@608: 
renatofilho@754: /*
renatofilho@754:  * HeaderLoad: 
renatofilho@608:  */
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_header_load(GstNuvDemux * nuv, nuv_header * h)
renatofilho@608: {
renatofilho@754:     GstBuffer      *buffer = NULL;
renatofilho@754:     GstFlowReturn   res = gst_nuv_demux_read_bytes(nuv, 72, TRUE, &buffer);
renatofilho@608: 
renatofilho@754:     if ((res != GST_FLOW_OK) || (buffer == NULL)) {
renatofilho@754:         goto done;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (h != NULL) {
renatofilho@754:         memcpy(h->id, buffer->data, 12);
renatofilho@754:         memcpy(h->version, buffer->data + 12, 5);
renatofilho@754:         h->i_width = GST_READ_UINT32_LE(&buffer->data[20]);
renatofilho@754:         h->i_height = GST_READ_UINT32_LE(&buffer->data[24]);
renatofilho@754:         h->i_width_desired = GST_READ_UINT32_LE(&buffer->data[28]);
renatofilho@754:         h->i_height_desired = GST_READ_UINT32_LE(&buffer->data[32]);
renatofilho@754:         h->i_mode = GPOINTER_TO_INT(buffer->data[36]);
renatofilho@754:         h->d_aspect = READ_DOUBLE_FROM_LE(&buffer->data[40]);
renatofilho@754:         h->d_fps = READ_DOUBLE_FROM_LE(&buffer->data[48]);
renatofilho@754:         /*
renatofilho@754:          * get the num and denom values from fps 
renatofilho@754:          */
renatofilho@754:         double2fraction(h->d_fps, &h->i_fpsn, &h->i_fpsd);
renatofilho@754:         h->i_video_blocks = GST_READ_UINT32_LE(&buffer->data[56]);
renatofilho@754:         h->i_audio_blocks = GST_READ_UINT32_LE(&buffer->data[60]);
renatofilho@754:         h->i_text_blocks = GST_READ_UINT32_LE(&buffer->data[64]);
renatofilho@754:         h->i_keyframe_distance = GST_READ_UINT32_LE(&buffer->data[68]);
renatofilho@608: 
renatofilho@754:         GST_DEBUG_OBJECT(nuv,
renatofilho@754:                          "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d",
renatofilho@754:                          h->id, h->version, h->i_width, h->i_height,
renatofilho@754:                          h->d_aspect, h->d_fps, h->i_video_blocks,
renatofilho@754:                          h->i_audio_blocks, h->i_text_blocks,
renatofilho@754:                          h->i_keyframe_distance);
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:   done:
renatofilho@754:     if (buffer != NULL) {
renatofilho@754:         gst_buffer_unref(buffer);
renatofilho@754:         buffer = NULL;
renatofilho@754:     }
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_stream_header_data(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   res;
renatofilho@608: 
renatofilho@754:     if (nuv->priv->new_file)
renatofilho@754:         res = gst_nuv_demux_header_load(nuv, NULL);
renatofilho@754:     else
renatofilho@754:         res = gst_nuv_demux_header_load(nuv, &nuv->priv->h);
renatofilho@714: 
renatofilho@754:     if (res == GST_FLOW_OK)
renatofilho@754:         nuv->priv->state = GST_NUV_DEMUX_EXTRA_DATA;
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: /*
renatofilho@608:  * Read NUV file tag
renatofilho@608:  */
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_stream_file_header(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   res = GST_FLOW_OK;
renatofilho@754:     GstBuffer      *file_header = NULL;
renatofilho@608: 
renatofilho@754:     res = gst_nuv_demux_read_bytes(nuv, 12, FALSE, &file_header);
renatofilho@754:     if (res == GST_FLOW_OK) {
renatofilho@754:         if (strncmp((gchar *) file_header->data, "MythTVVideo", 11) ||
renatofilho@754:             strncmp((gchar *) file_header->data, "NuppelVideo", 11)) {
renatofilho@754:             nuv->priv->state = GST_NUV_DEMUX_HEADER_DATA;
renatofilho@754:         } else {
renatofilho@754:             GST_DEBUG_OBJECT(nuv, "error parsing file header");
renatofilho@754:             nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
renatofilho@754:             res = GST_FLOW_ERROR;
renatofilho@754:         }
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (file_header != NULL) {
renatofilho@754:         gst_buffer_unref(file_header);
renatofilho@754:         file_header = NULL;
renatofilho@754:     }
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: /*
renatofilho@754:  * FrameHeaderLoad: 
renatofilho@608:  */
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_frame_header_load(GstNuvDemux * nuv, nuv_frame_header * h)
renatofilho@608: {
renatofilho@754:     unsigned char  *data;
renatofilho@754:     GstBuffer      *buf = NULL;
renatofilho@608: 
renatofilho@754:     GstFlowReturn   res = gst_nuv_demux_read_bytes(nuv, 12, TRUE, &buf);
renatofilho@608: 
renatofilho@754:     if ((res != GST_FLOW_OK) || (buf == NULL)) {
renatofilho@754:         goto done;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (h == NULL)
renatofilho@754:         goto done;
renatofilho@751: 
renatofilho@754:     data = buf->data;
renatofilho@608: 
renatofilho@754:     h->i_type = GPOINTER_TO_INT(data[0]);
renatofilho@754:     h->i_compression = GPOINTER_TO_INT(data[1]);
renatofilho@754:     h->i_keyframe = GPOINTER_TO_INT(data[2]);
renatofilho@754:     h->i_filters = GPOINTER_TO_INT(data[3]);
renatofilho@754:     h->i_timecode = GST_READ_UINT32_LE(&data[4]);
renatofilho@754:     h->i_length = GST_READ_UINT32_LE(&data[8]);
renatofilho@608: 
renatofilho@754:     GST_DEBUG_OBJECT(nuv,
renatofilho@754:                      "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d",
renatofilho@754:                      h->i_type, h->i_compression ? h->i_compression : ' ',
renatofilho@754:                      h->i_keyframe ? h->i_keyframe : ' ', h->i_filters,
renatofilho@754:                      h->i_timecode, h->i_length);
renatofilho@608: 
renatofilho@754:   done:
renatofilho@754:     if (buf != NULL) {
renatofilho@754:         gst_buffer_unref(buf);
renatofilho@754:         buf = NULL;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@754: gst_nuv_demux_extended_header_load(GstNuvDemux * nuv,
renatofilho@754:                                    nuv_extended_header * h)
renatofilho@608: {
renatofilho@754:     unsigned char  *data;
renatofilho@754:     GstBuffer      *buff = NULL;
renatofilho@608: 
renatofilho@754:     GstFlowReturn   res = gst_nuv_demux_read_bytes(nuv, 512, TRUE, &buff);
renatofilho@608: 
renatofilho@754:     if ((res != GST_FLOW_OK) || (buff == NULL)) {
renatofilho@754:         goto done;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (h == NULL)
renatofilho@754:         goto done;
renatofilho@714: 
renatofilho@754:     data = buff->data;
renatofilho@754:     h->i_version = GST_READ_UINT32_LE(&data[0]);
renatofilho@754:     h->i_video_fcc = GST_MAKE_FOURCC(data[4], data[5], data[6], data[7]);
renatofilho@754:     h->i_audio_fcc = GST_MAKE_FOURCC(data[8], data[9], data[10], data[11]);
renatofilho@754:     h->i_audio_sample_rate = GST_READ_UINT32_LE(&data[12]);
renatofilho@754:     h->i_audio_bits_per_sample = GST_READ_UINT32_LE(&data[16]);
renatofilho@754:     h->i_audio_channels = GST_READ_UINT32_LE(&data[20]);
renatofilho@754:     h->i_audio_compression_ratio = GST_READ_UINT32_LE(&data[24]);
renatofilho@754:     h->i_audio_quality = GST_READ_UINT32_LE(&data[28]);
renatofilho@754:     h->i_rtjpeg_quality = GST_READ_UINT32_LE(&data[32]);
renatofilho@754:     h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE(&data[36]);
renatofilho@754:     h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE(&data[40]);
renatofilho@754:     h->i_lavc_bitrate = GST_READ_UINT32_LE(&data[44]);
renatofilho@754:     h->i_lavc_qmin = GST_READ_UINT32_LE(&data[48]);
renatofilho@754:     h->i_lavc_qmin = GST_READ_UINT32_LE(&data[52]);
renatofilho@754:     h->i_lavc_maxqdiff = GST_READ_UINT32_LE(&data[56]);
renatofilho@754:     h->i_seekable_offset = GST_READ_UINT64_LE(&data[60]);
renatofilho@754:     h->i_keyframe_adjust_offset = GST_READ_UINT64_LE(&data[68]);
renatofilho@608: 
renatofilho@754:     GST_DEBUG_OBJECT(nuv,
renatofilho@754:                      "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d"
renatofilho@754:                      "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld",
renatofilho@754:                      h->i_version, (gchar *) & h->i_video_fcc,
renatofilho@754:                      (gchar *) & h->i_audio_fcc, h->i_audio_sample_rate,
renatofilho@754:                      h->i_audio_bits_per_sample, h->i_audio_channels,
renatofilho@754:                      h->i_audio_compression_ratio, h->i_audio_quality,
renatofilho@754:                      h->i_rtjpeg_quality, h->i_rtjpeg_luma_filter,
renatofilho@754:                      h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate,
renatofilho@754:                      h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff,
renatofilho@754:                      h->i_seekable_offset, h->i_keyframe_adjust_offset);
renatofilho@608: 
renatofilho@754:   done:
renatofilho@754:     if (buff != NULL) {
renatofilho@754:         gst_buffer_unref(buff);
renatofilho@754:         buff = NULL;
renatofilho@754:     }
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: 
renatofilho@754: /*
renatofilho@754:  * Query Functions 
renatofilho@754:  */
renatofilho@608: static const GstQueryType *
renatofilho@751: gst_nuv_demux_get_src_query_types(GstPad * pad)
renatofilho@608: {
renatofilho@754:     static const GstQueryType src_types[] = {
renatofilho@754:         GST_QUERY_POSITION,
renatofilho@754:         GST_QUERY_DURATION,
renatofilho@754:         0
renatofilho@754:     };
renatofilho@608: 
renatofilho@754:     return src_types;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_handle_src_query(GstPad * pad, GstQuery * query)
renatofilho@608: {
renatofilho@754:     gboolean        res = FALSE;
renatofilho@754:     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
renatofilho@608: 
renatofilho@674: 
renatofilho@754:     switch (GST_QUERY_TYPE(query)) {
renatofilho@754:     case GST_QUERY_POSITION:
renatofilho@754:         {
renatofilho@754:             GstFormat       format;
renatofilho@754:             gst_query_parse_position(query, &format, NULL);
renatofilho@754:             switch (format) {
renatofilho@754:             case GST_FORMAT_TIME:
renatofilho@754:                 if (GST_CLOCK_TIME_IS_VALID(nuv->priv->last_frame_time)) {
renatofilho@754:                     gst_query_set_position(query, GST_FORMAT_TIME,
renatofilho@754:                                            nuv->priv->last_frame_time);
renatofilho@754:                     res = TRUE;
renatofilho@754:                 }
renatofilho@754:                 break;
renatofilho@754:             default:
renatofilho@754:                 break;
renatofilho@754:             }
renatofilho@754:             break;
renatofilho@754:         }
renatofilho@754:     case GST_QUERY_DURATION:
renatofilho@754:         {
renatofilho@754:             GstFormat       format;
renatofilho@754:             gst_query_parse_duration(query, &format, NULL);
renatofilho@754:             switch (format) {
renatofilho@754:             case GST_FORMAT_TIME:
renatofilho@754:                 if (nuv->priv->duration_time != GST_CLOCK_TIME_NONE) {
renatofilho@754:                     gst_query_set_duration(query, GST_FORMAT_TIME,
renatofilho@754:                                            nuv->priv->duration_time);
renatofilho@754:                     res = TRUE;
renatofilho@754:                 }
renatofilho@754:                 break;
renatofilho@754:             default:
renatofilho@754:                 break;
renatofilho@754:             }
renatofilho@754:             break;
renatofilho@754:         }
renatofilho@754:     default:
renatofilho@754:         break;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (res == FALSE) {
renatofilho@754:         res = gst_pad_query_default(pad, query);
renatofilho@754:     }
renatofilho@674: 
renatofilho@754:     gst_object_unref(nuv);
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static GstPad  *
renatofilho@751: gst_nuv_demux_create_pad(GstNuvDemux * nuv, GstCaps * caps,
renatofilho@754:                          GstStaticPadTemplate * template,
renatofilho@754:                          const gchar * name)
renatofilho@608: {
renatofilho@754:     GstPad         *pad = NULL;
renatofilho@754:     pad = gst_pad_new_from_static_template(template, name);
renatofilho@754:     gst_pad_set_caps(pad, caps);
renatofilho@754:     gst_pad_set_active(pad, TRUE);
renatofilho@754:     gst_pad_use_fixed_caps(pad);
renatofilho@754:     gst_element_add_pad(GST_ELEMENT(nuv), pad);
renatofilho@608: 
renatofilho@754:     gst_pad_set_event_function(pad,
renatofilho@754:                                GST_DEBUG_FUNCPTR
renatofilho@754:                                (gst_nuv_demux_srcpad_event));
renatofilho@608: 
renatofilho@754:     gst_pad_set_query_type_function(pad,
renatofilho@754:                                     GST_DEBUG_FUNCPTR
renatofilho@754:                                     (gst_nuv_demux_get_src_query_types));
renatofilho@608: 
renatofilho@754:     gst_pad_set_query_function(pad,
renatofilho@754:                                GST_DEBUG_FUNCPTR
renatofilho@754:                                (gst_nuv_demux_handle_src_query));
renatofilho@608: 
renatofilho@751: 
renatofilho@754:     return pad;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_create_pads(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@822:     if ((nuv->priv->src_video_pad != NULL) || 
renatofilho@822:         (nuv->priv->src_audio_pad != NULL)) {
renatofilho@822:         return;
renatofilho@822:     }
renatofilho@822: 
renatofilho@822:     if (nuv->priv->h.i_video_blocks != 0){
renatofilho@822:         GstCaps *video_caps = NULL;
renatofilho@608: 
renatofilho@754:         video_caps = gst_caps_new_simple("video/x-divx",
renatofilho@754:                                          "divxversion", G_TYPE_INT, 4,
renatofilho@754:                                          "width", G_TYPE_INT,
renatofilho@754:                                          nuv->priv->h.i_width, "height",
renatofilho@754:                                          G_TYPE_INT, nuv->priv->h.i_height,
renatofilho@754:                                          "framerate", GST_TYPE_FRACTION,
renatofilho@754:                                          nuv->priv->h.i_fpsn,
renatofilho@754:                                          nuv->priv->h.i_fpsd, "format",
renatofilho@754:                                          GST_TYPE_FOURCC,
renatofilho@754:                                          nuv->priv->eh.i_video_fcc,
renatofilho@754:                                          "pixel-aspect-ratio",
renatofilho@754:                                          GST_TYPE_FRACTION,
renatofilho@754:                                          (gint) (nuv->priv->h.d_aspect *
renatofilho@754:                                                  1000.0f), 1000, NULL);
renatofilho@608: 
renatofilho@754:         nuv->priv->src_video_pad =
renatofilho@754:             gst_nuv_demux_create_pad(nuv, video_caps, &video_src_template,
renatofilho@754:                                      "video_src");
renatofilho@754:         gst_caps_unref(video_caps);
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (nuv->priv->h.i_audio_blocks != 0) {
renatofilho@822:         GstCaps *audio_caps = NULL;
renatofilho@608: 
renatofilho@822:         audio_caps = gst_caps_new_simple("audio/mpeg",
renatofilho@822:                                          "rate", G_TYPE_INT, nuv->priv->eh.i_audio_sample_rate,
renatofilho@822:                                          "format", GST_TYPE_FOURCC, nuv->priv->eh.i_audio_fcc,
renatofilho@822:                                          "channels", G_TYPE_INT, nuv->priv->eh.i_audio_channels,
renatofilho@822:                                          "layer", G_TYPE_INT, 3, // fixme: magic number
renatofilho@822:                                          "mpegversion", G_TYPE_INT, nuv->priv->eh.i_version,
renatofilho@822:                                          NULL);
renatofilho@608: 
renatofilho@754:         nuv->priv->src_audio_pad =
renatofilho@754:             gst_nuv_demux_create_pad(nuv, audio_caps, &audio_src_template,
renatofilho@754:                                      "audio_src");
renatofilho@754:         gst_caps_unref(audio_caps);
renatofilho@754:     }
renatofilho@751: 
renatofilho@754:     gst_element_no_more_pads(GST_ELEMENT(nuv));
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_validate_header(nuv_frame_header * h)
renatofilho@608: {
renatofilho@754:     gboolean        valid = FALSE;
renatofilho@754:     // g_usleep (1 * G_USEC_PER_SEC );
renatofilho@754:     switch (h->i_type) {
renatofilho@754:         /*
renatofilho@754:          * case 'V': if (h->i_compression == 0 || h->i_compression == 1 ||
renatofilho@754:          * h->i_compression == 2 || h->i_compression == 'N' ||
renatofilho@754:          * h->i_compression == 'L') { valid = TRUE; } break; case 'A': if
renatofilho@754:          * (h->i_compression == 0 || h->i_compression == 1 ||
renatofilho@754:          * h->i_compression == 2 || h->i_compression == 3 ||
renatofilho@754:          * h->i_compression == 'F' || h->i_compression == 'S' ||
renatofilho@754:          * h->i_compression == 'N' || h->i_compression == 'L') { valid =
renatofilho@754:          * TRUE; } break; case 'S': if (h->i_compression == 'B' ||
renatofilho@754:          * h->i_compression == 'A' || h->i_compression == 'V' ||
renatofilho@754:          * h->i_compression == 'S') { valid = TRUE; } break; 
renatofilho@754:          */
renatofilho@754:     case 'A':
renatofilho@608:     case 'V':
renatofilho@608:     case 'S':
renatofilho@754:     case 'R':
renatofilho@754:     case 'D':
renatofilho@754:     case 'Q':
renatofilho@754:         valid = TRUE;
renatofilho@754:         break;
renatofilho@754:     default:
renatofilho@754:         valid = FALSE;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     return valid;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_read_head_frame(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
renatofilho@754:     gboolean        valid = FALSE;
renatofilho@608: 
renatofilho@754:     do {
renatofilho@754:         ret = gst_nuv_demux_frame_header_load(nuv, &nuv->priv->fh);
renatofilho@754:         if (ret != GST_FLOW_OK) {
renatofilho@754:             return ret;
renatofilho@754:         }
renatofilho@608: 
renatofilho@754:         if (gst_nuv_demux_validate_header(&nuv->priv->fh) == TRUE)
renatofilho@754:             valid = TRUE;
renatofilho@608: 
renatofilho@754:     }
renatofilho@754:     while (valid == FALSE);
renatofilho@608: 
renatofilho@754:     nuv->priv->state = GST_NUV_DEMUX_MOVI;
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_combine_flow(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret_video = nuv->priv->last_video_return;
renatofilho@754:     GstFlowReturn   ret_audio = nuv->priv->last_audio_return;
renatofilho@608: 
renatofilho@754:     if ((ret_video != GST_FLOW_OK) && (ret_audio != GST_FLOW_OK))
renatofilho@754:         return FALSE;
renatofilho@608: 
renatofilho@754:     if (GST_FLOW_IS_FATAL(ret_video))
renatofilho@754:         return FALSE;
renatofilho@608: 
renatofilho@754:     if (GST_FLOW_IS_FATAL(ret_audio))
renatofilho@754:         return FALSE;
renatofilho@608: 
renatofilho@754:     return TRUE;
renatofilho@608: }
renatofilho@608: 
renatofilho@822: static GstFlowReturn
renatofilho@751: gst_nuv_demux_stream_data(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
renatofilho@754:     GstPad         *pad = NULL;
renatofilho@754:     guint64         timestamp;
renatofilho@754:     GstBuffer      *buf = NULL;
renatofilho@754:     nuv_frame_header h;
renatofilho@608: 
renatofilho@754:     h = nuv->priv->fh;
renatofilho@608: 
renatofilho@754:     if (h.i_type == 'R') {
renatofilho@754:         goto done;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (h.i_length > 0) {
renatofilho@754:         ret = gst_nuv_demux_read_bytes(nuv, h.i_length, TRUE, &buf);
renatofilho@754:         if ((ret != GST_FLOW_OK) || (buf == NULL)) {
renatofilho@754:             goto done;
renatofilho@754:         }
renatofilho@751: 
renatofilho@754:         if ((h.i_timecode < 0)) {
renatofilho@754:             h.i_timecode = 0;
renatofilho@754:             // goto done;
renatofilho@754:         }
renatofilho@751: 
renatofilho@754:         timestamp = h.i_timecode * GST_MSECOND;
renatofilho@754:         GST_BUFFER_TIMESTAMP(buf) = timestamp;
renatofilho@754:     } else {
renatofilho@754:         goto done;
renatofilho@754:     }
renatofilho@751: 
renatofilho@751: 
renatofilho@754:     switch (h.i_type) {
renatofilho@754:     case 'V':
renatofilho@754:         {
renatofilho@754:             pad = nuv->priv->src_video_pad;
renatofilho@751: 
renatofilho@754:             if (nuv->priv->new_video_segment) {
renatofilho@751: 
renatofilho@754:                 /*
renatofilho@754:                  * send new segment event 
renatofilho@754:                  */
renatofilho@754:                 gst_pad_push_event(nuv->priv->src_video_pad,
renatofilho@754:                                    gst_event_new_new_segment(TRUE, 1.0,
renatofilho@754:                                                              GST_FORMAT_TIME,
renatofilho@754:                                                              0,
renatofilho@754:                                                              GST_CLOCK_TIME_NONE,
renatofilho@754:                                                              0));
renatofilho@751: 
renatofilho@754:                 if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
renatofilho@754:                     nuv->priv->time_start = timestamp;
renatofilho@754:                 }
renatofilho@754:                 nuv->priv->new_video_segment = FALSE;
renatofilho@754:             }
renatofilho@751: 
renatofilho@754:             break;
renatofilho@754:         }
renatofilho@754:     case 'A':
renatofilho@754:         {
renatofilho@754:             pad = nuv->priv->src_audio_pad;
renatofilho@751: 
renatofilho@754:             if (nuv->priv->new_audio_segment) {
renatofilho@754:                 /*
renatofilho@754:                  * send new segment event 
renatofilho@754:                  */
renatofilho@754:                 gst_pad_push_event(nuv->priv->src_audio_pad,
renatofilho@754:                                    gst_event_new_new_segment(TRUE, 1.0,
renatofilho@754:                                                              GST_FORMAT_TIME,
renatofilho@754:                                                              0,
renatofilho@754:                                                              GST_CLOCK_TIME_NONE,
renatofilho@754:                                                              0));
renatofilho@751: 
renatofilho@754:                 if (nuv->priv->time_start == GST_CLOCK_TIME_NONE) {
renatofilho@754:                     nuv->priv->time_start = timestamp;
renatofilho@754:                 }
renatofilho@754:                 nuv->priv->new_audio_segment = FALSE;
renatofilho@754:             }
renatofilho@751: 
renatofilho@754:             break;
renatofilho@754:         }
renatofilho@754:     case 'S':
renatofilho@754:         {
renatofilho@754:             switch (h.i_compression) {
renatofilho@754:             case 'V':
renatofilho@754:                 GST_DEBUG_OBJECT(nuv, "sending new video segment: %d",
renatofilho@754:                                  h.i_timecode);
renatofilho@754:                 gst_pad_push_event(nuv->priv->src_video_pad,
renatofilho@754:                                    gst_event_new_new_segment(TRUE, 1.0,
renatofilho@754:                                                              GST_FORMAT_TIME,
renatofilho@754:                                                              h.i_timecode *
renatofilho@754:                                                              GST_MSECOND,
renatofilho@754:                                                              GST_CLOCK_TIME_NONE,
renatofilho@754:                                                              0));
renatofilho@754:                 break;
renatofilho@754:             case 'A':
renatofilho@754:                 GST_DEBUG_OBJECT(nuv, "sending new audio segment: %d",
renatofilho@754:                                  h.i_timecode);
renatofilho@754:                 gst_pad_push_event(nuv->priv->src_audio_pad,
renatofilho@754:                                    gst_event_new_new_segment(TRUE, 1.0,
renatofilho@754:                                                              GST_FORMAT_TIME,
renatofilho@754:                                                              0,
renatofilho@754:                                                              GST_CLOCK_TIME_NONE,
renatofilho@754:                                                              0));
renatofilho@754:                 break;
renatofilho@754:             default:
renatofilho@754:                 break;
renatofilho@754:             }
renatofilho@754:             goto done;
renatofilho@754:         }
renatofilho@754:     default:
renatofilho@754:         break;
renatofilho@754:     }
renatofilho@751: 
renatofilho@754:     if ((buf != NULL) && (pad != NULL)) {
renatofilho@754:         /*
renatofilho@754:          * pushing the buffer 
renatofilho@754:          */
renatofilho@754:         gst_buffer_set_caps(buf, GST_PAD_CAPS(pad));
renatofilho@754:         ret = gst_pad_push(pad, buf);
renatofilho@754:         buf = NULL;
renatofilho@751: 
renatofilho@754:         if (ret != GST_FLOW_OK) {
renatofilho@754:             GST_WARNING_OBJECT(nuv, "error: %d pushing on srcpad %s", ret,
renatofilho@754:                                gst_pad_get_name(pad));
renatofilho@751: 
renatofilho@754:             if (pad == nuv->priv->src_video_pad) {
renatofilho@754:                 nuv->priv->last_video_return = ret;
renatofilho@754:             } else if (pad == nuv->priv->src_audio_pad) {
renatofilho@754:                 nuv->priv->last_audio_return = ret;
renatofilho@754:             }
renatofilho@751: 
renatofilho@754:             /*
renatofilho@754:              * verify anothers flow if is necessary stop task 
renatofilho@754:              */
renatofilho@754:             if (gst_nuv_combine_flow(nuv) != FALSE) {
renatofilho@754:                 ret = GST_FLOW_OK;
renatofilho@754:             } else {
renatofilho@754:                 GST_WARNING_OBJECT(nuv, "error: on push");
renatofilho@754:             }
renatofilho@751: 
renatofilho@754:         }
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:   done:
renatofilho@754:     if (buf != NULL) {
renatofilho@754:         gst_buffer_unref(buf);
renatofilho@754:         buf = NULL;
renatofilho@754:     }
renatofilho@754:     if (ret == GST_FLOW_OK) {
renatofilho@754:         nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
renatofilho@754:         memset(&nuv->priv->fh, 0, sizeof(nuv->priv->fh));
renatofilho@754:     }
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_stream_mpeg_data(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * ffmpeg extra data 
renatofilho@754:      */
renatofilho@754:     if (nuv->priv->new_file) {
renatofilho@754:         GstBuffer      *buf;
renatofilho@754:         ret =
renatofilho@754:             gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE,
renatofilho@754:                                      &buf);
renatofilho@754:         gst_buffer_unref(buf);
renatofilho@754:     } else {
renatofilho@754:         ret =
renatofilho@754:             gst_nuv_demux_read_bytes(nuv, nuv->priv->mpeg_data_size, TRUE,
renatofilho@754:                                      &nuv->priv->mpeg_buffer);
renatofilho@754:     }
renatofilho@714: 
renatofilho@754:     if ((ret != GST_FLOW_OK) || (nuv->priv->mpeg_buffer == NULL)) {
renatofilho@754:         return ret;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     GST_BUFFER_SIZE(nuv->priv->mpeg_buffer) = nuv->priv->mpeg_data_size;
renatofilho@754:     nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_stream_extra_data(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * Load 'D' 
renatofilho@754:      */
renatofilho@754:     nuv_frame_header h;
renatofilho@608: 
renatofilho@754:     if (nuv->priv->new_file)
renatofilho@754:         ret = gst_nuv_demux_frame_header_load(nuv, NULL);
renatofilho@754:     else
renatofilho@754:         ret = gst_nuv_demux_frame_header_load(nuv, &h);
renatofilho@714: 
renatofilho@754:     if (ret != GST_FLOW_OK)
renatofilho@754:         return ret;
renatofilho@608: 
renatofilho@754:     if (h.i_type != 'D') {
renatofilho@754:         GST_WARNING_OBJECT(nuv, "Unsuported rtjpeg");
renatofilho@754:         return GST_FLOW_NOT_SUPPORTED;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (h.i_length > 0) {
renatofilho@754:         if (h.i_compression == 'F') {
renatofilho@754:             nuv->priv->state = GST_NUV_DEMUX_MPEG_DATA;
renatofilho@754:         } else {
renatofilho@754:             GST_WARNING_OBJECT(nuv,
renatofilho@754:                                "only file with extended chunk are supported");
renatofilho@754:             return GST_FLOW_NOT_SUPPORTED;
renatofilho@754:         }
renatofilho@754:     } else {
renatofilho@754:         nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_stream_extend_header_data(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
renatofilho@608: 
renatofilho@754:     if (nuv->priv->new_file)
renatofilho@754:         ret = gst_nuv_demux_extended_header_load(nuv, NULL);
renatofilho@754:     else {
renatofilho@754:         ret = gst_nuv_demux_extended_header_load(nuv, &nuv->priv->eh);
renatofilho@754:         if (ret != GST_FLOW_OK)
renatofilho@754:             return ret;
renatofilho@754:         gst_nuv_demux_create_pads(nuv);
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     nuv->priv->state = GST_NUV_DEMUX_INDEX_CREATE;
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_stream_extend_header(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstBuffer      *buf = NULL;
renatofilho@754:     GstFlowReturn   res = GST_FLOW_OK;
renatofilho@608: 
renatofilho@754:     res = gst_nuv_demux_read_bytes(nuv, 1, FALSE, &buf);
renatofilho@754:     if ((res != GST_FLOW_OK) || (buf == NULL)) {
renatofilho@754:         if (buf != NULL) {
renatofilho@754:             gst_buffer_unref(buf);
renatofilho@754:         }
renatofilho@754:         return res;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (buf->data[0] == 'X') {
renatofilho@754:         gst_buffer_unref(buf);
renatofilho@754:         buf = NULL;
renatofilho@754:         nuv_frame_header h;
renatofilho@608: 
renatofilho@754:         res = gst_nuv_demux_frame_header_load(nuv, &h);
renatofilho@754:         if (res != GST_FLOW_OK)
renatofilho@754:             return res;
renatofilho@608: 
renatofilho@754:         if (h.i_length != 512) {
renatofilho@754:             return GST_FLOW_ERROR;
renatofilho@754:         }
renatofilho@754:         nuv->priv->state = GST_NUV_DEMUX_EXTEND_HEADER_DATA;
renatofilho@754:     } else {
renatofilho@754:         nuv->priv->state = GST_NUV_DEMUX_INVALID_DATA;
renatofilho@754:         g_object_unref(buf);
renatofilho@754:         GST_ELEMENT_WARNING(nuv, STREAM, FAILED,
renatofilho@754:                             (_("incomplete NUV support")),
renatofilho@754:                             ("incomplete NUV support"));
renatofilho@754:         return GST_FLOW_ERROR;
renatofilho@754:     }
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_create_seek_index(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     GstMessage     *msg;
renatofilho@754:     nuv_frame_header h;
renatofilho@608: 
renatofilho@754:     while (gst_nuv_demux_frame_header_load(nuv, &h) == GST_FLOW_OK) {
renatofilho@754:         if ((h.i_type == 'V') && (h.i_keyframe == 0)) {
renatofilho@754:             frame_index_data *f = g_new0(frame_index_data, 1);
renatofilho@608: 
renatofilho@754:             f->offset = nuv->priv->offset - 12;
renatofilho@754:             f->timecode = h.i_timecode * GST_MSECOND;
renatofilho@608: 
renatofilho@754:             nuv->priv->index = g_slist_append(nuv->priv->index, f);
renatofilho@754:         }
renatofilho@754:         if (h.i_type != 'R') {
renatofilho@754:             nuv->priv->offset += h.i_length;
renatofilho@754:             if (h.i_type == 'A' || h.i_type == 'V')
renatofilho@754:                 nuv->priv->duration_time = h.i_timecode * GST_MSECOND;
renatofilho@754:         }
renatofilho@754:     }
renatofilho@754:     GST_DEBUG_OBJECT(nuv,
renatofilho@754:                      "CREATING INDEX: DONE : DURATION Bytes/Sec: %"
renatofilho@754:                      G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
renatofilho@754:                      nuv->priv->offset, nuv->priv->duration_time);
renatofilho@751: 
renatofilho@754:     nuv->priv->duration_bytes = nuv->priv->offset;
renatofilho@754:     nuv->priv->offset = nuv->priv->header_lengh;
renatofilho@608: 
renatofilho@754:     msg =
renatofilho@754:         gst_message_new_duration(GST_OBJECT(nuv), GST_FORMAT_TIME,
renatofilho@754:                                  nuv->priv->duration_time);
renatofilho@754:     gst_element_post_message(GST_ELEMENT(nuv), msg);
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_play(GstPad * pad)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   res = GST_FLOW_OK;
renatofilho@754:     GstNuvDemux    *nuv = GST_NUV_DEMUX(GST_PAD_PARENT(pad));
renatofilho@608: 
renatofilho@754:     switch (nuv->priv->state) {
renatofilho@754:     case GST_NUV_DEMUX_START:
renatofilho@754:         res = gst_nuv_demux_stream_file_header(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_HEADER_DATA:
renatofilho@754:         res = gst_nuv_demux_stream_header_data(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_EXTRA_DATA:
renatofilho@754:         res = gst_nuv_demux_stream_extra_data(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_MPEG_DATA:
renatofilho@754:         res = gst_nuv_demux_stream_mpeg_data(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_EXTEND_HEADER:
renatofilho@754:         res = gst_nuv_demux_stream_extend_header(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_EXTEND_HEADER_DATA:
renatofilho@754:         res = gst_nuv_demux_stream_extend_header_data(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         // store file header size
renatofilho@754:         nuv->priv->header_lengh = nuv->priv->offset;
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_INDEX_CREATE:
renatofilho@754:         if ((nuv->priv->mode == NUV_PULL_MODE) && (!nuv->priv->new_file)) {
renatofilho@754:             gst_nuv_demux_create_seek_index(nuv);
renatofilho@754:         }
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_FRAME_HEADER:
renatofilho@754:         res = gst_nuv_demux_read_head_frame(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_MOVI:
renatofilho@754:         res = gst_nuv_demux_stream_data(nuv);
renatofilho@754:         if ((res != GST_FLOW_OK) && (res != GST_FLOW_ERROR_NO_DATA)) {
renatofilho@754:             goto pause;
renatofilho@754:         }
renatofilho@754:         break;
renatofilho@608: 
renatofilho@754:     case GST_NUV_DEMUX_INVALID_DATA:
renatofilho@754:         goto pause;
renatofilho@754:         break;
renatofilho@754:     default:
renatofilho@754:         g_assert_not_reached();
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     return GST_FLOW_OK;
renatofilho@608: 
renatofilho@754:   pause:
renatofilho@754:     GST_LOG_OBJECT(nuv, "pausing task, reason %s", gst_flow_get_name(res));
renatofilho@754:     gst_pad_pause_task(nuv->priv->sinkpad);
renatofilho@608: 
renatofilho@754:     if (res == GST_FLOW_ERROR_EOS) {
renatofilho@754:         gst_nuv_demux_send_eos(nuv);
renatofilho@754:         nuv->priv->eos = TRUE;
renatofilho@754:         res = GST_FLOW_OK;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (GST_FLOW_IS_FATAL(res)) {
renatofilho@754:         GST_ELEMENT_ERROR(nuv, STREAM, FAILED,
renatofilho@754:                           (_("Internal data stream error.")),
renatofilho@754:                           ("streaming stopped, reason %s",
renatofilho@754:                            gst_flow_get_name(res)));
renatofilho@608: 
renatofilho@754:         gst_nuv_demux_send_eos(nuv);
renatofilho@754:     }
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_send_eos(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     gst_element_post_message(GST_ELEMENT(nuv),
renatofilho@754:                              gst_message_new_segment_done(GST_OBJECT(nuv),
renatofilho@754:                                                           GST_FORMAT_TIME,
renatofilho@754:                                                           -1));
renatofilho@608: 
renatofilho@754:     if (nuv->priv->src_video_pad)
renatofilho@754:         gst_pad_push_event(nuv->priv->src_video_pad, gst_event_new_eos());
renatofilho@754:     if (nuv->priv->src_audio_pad)
renatofilho@754:         gst_pad_push_event(nuv->priv->src_audio_pad, gst_event_new_eos());
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_read_bytes(GstNuvDemux * nuv, guint64 size, gboolean move,
renatofilho@754:                          GstBuffer ** buffer)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
renatofilho@608: 
renatofilho@754:     if (size == 0) {
renatofilho@754:         return ret;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (nuv->priv->mode == NUV_PULL_MODE) {
renatofilho@754:         ret =
renatofilho@754:             gst_pad_pull_range(nuv->priv->sinkpad, nuv->priv->offset, size,
renatofilho@754:                                buffer);
renatofilho@754:         if (ret == GST_FLOW_OK) {
renatofilho@754:             if (move) {
renatofilho@754:                 nuv->priv->offset += size;
renatofilho@754:             }
renatofilho@754:             /*
renatofilho@754:              * got eos 
renatofilho@754:              */
renatofilho@754:         } else if (ret == GST_FLOW_UNEXPECTED) {
renatofilho@754:             return GST_FLOW_ERROR_EOS;
renatofilho@754:         }
renatofilho@754:     } else {
renatofilho@754:         if (gst_adapter_available(nuv->priv->adapter) < size) {
renatofilho@754:             nuv->priv->more_data = TRUE;
renatofilho@754:             return GST_FLOW_ERROR_NO_DATA;
renatofilho@754:         }
renatofilho@754:         if (move) {
renatofilho@754:             *buffer = gst_adapter_take_buffer(nuv->priv->adapter, size);
renatofilho@754:         } else {
renatofilho@754:             guint8         *data = NULL;
renatofilho@754:             data = (guint8 *) gst_adapter_peek(nuv->priv->adapter, size);
renatofilho@754:             *buffer = gst_buffer_new();
renatofilho@754:             gst_buffer_set_data(*buffer, data, size);
renatofilho@754:         }
renatofilho@754:     }
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_move_bytes(GstNuvDemux * nuv, guint64 size)
rosfran@713: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
rosfran@713: 
renatofilho@754:     if (size == 0) {
renatofilho@754:         return ret;
renatofilho@754:     }
rosfran@713: 
renatofilho@754:     if (nuv->priv->mode == NUV_PULL_MODE) {
renatofilho@754:         nuv->priv->offset += size;
renatofilho@754:     } else {
renatofilho@754:         if (gst_adapter_available(nuv->priv->adapter) < size) {
renatofilho@754:             nuv->priv->more_data = TRUE;
renatofilho@754:             return GST_FLOW_ERROR_NO_DATA;
renatofilho@754:         }
renatofilho@754:         gst_adapter_flush(nuv->priv->adapter, size);
renatofilho@754:     }
renatofilho@754:     return ret;
rosfran@713: }
rosfran@713: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_sink_activate(GstPad * sinkpad)
renatofilho@608: {
renatofilho@754:     gboolean        res = TRUE;
renatofilho@754:     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
renatofilho@751: 
renatofilho@754:     if (gst_pad_check_pull_range(sinkpad)) {
renatofilho@754:         gst_adapter_clear(nuv->priv->adapter);
renatofilho@754:         res = gst_pad_activate_pull(sinkpad, TRUE);
renatofilho@754:     } else {
renatofilho@754:         gst_adapter_clear(nuv->priv->adapter);
renatofilho@754:         res = gst_pad_activate_push(sinkpad, TRUE);
renatofilho@754:     }
renatofilho@751: 
renatofilho@754:     g_object_unref(nuv);
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_sink_activate_pull(GstPad * sinkpad, gboolean active)
renatofilho@608: {
renatofilho@754:     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(sinkpad));
renatofilho@608: 
renatofilho@754:     if (active) {
renatofilho@754:         GST_DEBUG_OBJECT(nuv, "activating pull function");
renatofilho@754:         nuv->priv->mode = NUV_PULL_MODE;
renatofilho@754:         gst_adapter_clear(nuv->priv->adapter);
renatofilho@608: 
renatofilho@754:         gst_pad_start_task(sinkpad, (GstTaskFunction) gst_nuv_demux_loop,
renatofilho@754:                            sinkpad);
renatofilho@754:     } else {
renatofilho@754:         GST_DEBUG_OBJECT(nuv, "deactivating pull function");
renatofilho@754:         gst_pad_stop_task(sinkpad);
renatofilho@754:     }
renatofilho@754:     gst_object_unref(nuv);
renatofilho@608: 
renatofilho@754:     return TRUE;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_sink_activate_push(GstPad * pad, gboolean active)
renatofilho@608: {
renatofilho@754:     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
renatofilho@608: 
renatofilho@754:     if (active) {
renatofilho@754:         nuv->priv->mode = NUV_PUSH_MODE;
renatofilho@754:         gst_adapter_clear(nuv->priv->adapter);
renatofilho@608: 
renatofilho@754:         GST_DEBUG_OBJECT(nuv, "activating push/chain function");
renatofilho@754:     } else {
renatofilho@754:         GST_DEBUG_OBJECT(nuv, "deactivating push/chain function");
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     gst_object_unref(nuv);
renatofilho@608: 
renatofilho@754:     return TRUE;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static frame_index_data *
renatofilho@751: gst_nuv_demux_do_seek_index(GstNuvDemux * nuv, gint64 seek_pos,
renatofilho@754:                             gint64 segment_stop, GstFormat format)
renatofilho@608: {
renatofilho@754:     GSList         *l;
renatofilho@754:     frame_index_data *ret = NULL;
renatofilho@608: 
renatofilho@754:     if (nuv->priv->index == NULL) {
renatofilho@754:         return NULL;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * find keyframe closest to the requested position 
renatofilho@754:      */
renatofilho@754:     for (l = nuv->priv->index; l != NULL; l = l->next) {
renatofilho@754:         frame_index_data *f = (frame_index_data *) l->data;
renatofilho@754:         gint64          pos = 0;
renatofilho@608: 
renatofilho@754:         if (format == GST_FORMAT_BYTES) {
renatofilho@754:             pos = f->offset;
renatofilho@754:         } else if (format == GST_FORMAT_TIME) {
renatofilho@754:             pos = f->timecode;
renatofilho@754:         } else {
renatofilho@754:             return NULL;
renatofilho@754:         }
renatofilho@608: 
renatofilho@754:         if (pos >= seek_pos) {
renatofilho@754:             ret = f;
renatofilho@754:             break;
renatofilho@754:         }
renatofilho@751: 
renatofilho@754:         if ((segment_stop != -1) && (segment_stop != GST_CLOCK_TIME_NONE)
renatofilho@754:             && (pos > segment_stop)) {
renatofilho@754:             break;
renatofilho@754:         }
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_do_seek(GstNuvDemux * nuv, GstEvent * event)
renatofilho@608: {
renatofilho@754:     gdouble         rate;
renatofilho@754:     GstFormat       format;
renatofilho@754:     GstSeekFlags    flags;
renatofilho@754:     GstSeekType     cur_type;
renatofilho@754:     gint64          cur;
renatofilho@754:     GstSeekType     stop_type;
renatofilho@754:     gint64          stop;
renatofilho@754:     gboolean        flush;
renatofilho@754:     frame_index_data *entry;
renatofilho@754:     gint64          segment_start;
renatofilho@754:     gint64          segment_stop;
renatofilho@754:     GstEvent       *newsegment_event;
renatofilho@608: 
renatofilho@754:     if (nuv->priv->eos) {
renatofilho@754:         return FALSE;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (nuv->priv->mode == NUV_PUSH_MODE) {
renatofilho@754:         return FALSE;
renatofilho@754:     }
renatofilho@608: 
renatofilho@608: 
renatofilho@754:     gst_event_parse_seek(event, &rate, &format, &flags,
renatofilho@754:                          &cur_type, &cur, &stop_type, &stop);
renatofilho@608: 
renatofilho@608: 
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * if (format == GST_FORMAT_TIME) { GST_DEBUG_OBJECT (nuv, "Can only
renatofilho@754:      * seek on BYTES"); return FALSE; } 
renatofilho@754:      */
renatofilho@754: 
renatofilho@754:     if (rate <= 0.0) {
renatofilho@754:         GST_DEBUG_OBJECT(nuv, "Can only seek with positive rate");
renatofilho@754:         return FALSE;
renatofilho@754:     }
renatofilho@754: 
renatofilho@754:     if (cur_type == GST_SEEK_TYPE_SET) {
renatofilho@754:         GST_OBJECT_LOCK(nuv);
renatofilho@754:         if (gst_nuv_demux_do_seek_index(nuv, cur, -1, format) == NULL) {
renatofilho@754:             GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
renatofilho@754:             GST_OBJECT_UNLOCK(nuv);
renatofilho@754:             return FALSE;
renatofilho@754:         }
renatofilho@754:         GST_OBJECT_UNLOCK(nuv);
renatofilho@754:     }
renatofilho@754: 
renatofilho@754:     flush = !!(flags & GST_SEEK_FLAG_FLUSH);
renatofilho@754: 
renatofilho@754:     if (flush) {
renatofilho@754:         gst_pad_push_event(nuv->priv->sinkpad,
renatofilho@754:                            gst_event_new_flush_start());
renatofilho@754:         if (nuv->priv->src_video_pad != NULL) {
renatofilho@754:             gst_pad_push_event(nuv->priv->src_video_pad,
renatofilho@754:                                gst_event_new_flush_start());
renatofilho@754:         }
renatofilho@754: 
renatofilho@754:         if (nuv->priv->src_audio_pad != NULL) {
renatofilho@754:             gst_pad_push_event(nuv->priv->src_audio_pad,
renatofilho@754:                                gst_event_new_flush_start());
renatofilho@754:         }
renatofilho@754:     } else {
renatofilho@754:         gst_pad_pause_task(nuv->priv->sinkpad);
renatofilho@754:     }
renatofilho@754: 
renatofilho@754:     GST_PAD_STREAM_LOCK(nuv->priv->sinkpad);
renatofilho@754:     GST_OBJECT_LOCK(nuv);
renatofilho@754: 
renatofilho@754: 
renatofilho@754:     if (cur == GST_CLOCK_TIME_NONE)
renatofilho@754:         cur = 0;
renatofilho@754:     if (stop == GST_CLOCK_TIME_NONE)
renatofilho@754:         stop = nuv->priv->duration_time;
renatofilho@754: 
renatofilho@754:     if (cur_type == GST_SEEK_TYPE_SET)
renatofilho@754:         segment_start = cur;
renatofilho@754:     else if (cur_type == GST_SEEK_TYPE_CUR)
renatofilho@754:         segment_start = nuv->priv->segment_start + cur;
renatofilho@754:     else
renatofilho@754:         segment_start = nuv->priv->segment_start;
renatofilho@754: 
renatofilho@754:     if (stop_type == GST_SEEK_TYPE_SET)
renatofilho@754:         segment_stop = stop;
renatofilho@754:     else if (stop_type == GST_SEEK_TYPE_CUR)
renatofilho@754:         segment_stop = nuv->priv->segment_stop + stop;
renatofilho@754:     else
renatofilho@754:         segment_stop = nuv->priv->segment_stop;
renatofilho@754: 
renatofilho@754:     segment_start = CLAMP(segment_start, 0, nuv->priv->duration_time);
renatofilho@754:     segment_stop = CLAMP(segment_stop, 0, nuv->priv->duration_time);
renatofilho@754: 
renatofilho@754:     entry = gst_nuv_demux_do_seek_index(nuv, segment_start,
renatofilho@754:                                         segment_stop, format);
renatofilho@754: 
renatofilho@754:     if (entry == NULL) {
renatofilho@754:         GST_DEBUG_OBJECT(nuv, "No matching seek entry in index");
renatofilho@754:         goto seek_error;
renatofilho@754:     }
renatofilho@754: 
renatofilho@754:     segment_start = entry->timecode;
renatofilho@754: 
renatofilho@754:     nuv->priv->segment_start = segment_start;
renatofilho@754:     nuv->priv->segment_stop = segment_stop;
renatofilho@754: 
renatofilho@754:     GST_OBJECT_UNLOCK(nuv);
renatofilho@754: 
renatofilho@754:     if (!nuv->priv->eos) {
renatofilho@754:         GstMessage     *msg;
renatofilho@754:         msg =
renatofilho@754:             gst_message_new_segment_start(GST_OBJECT(nuv), GST_FORMAT_TIME,
renatofilho@754:                                           nuv->priv->segment_start);
renatofilho@754: 
renatofilho@754:         gst_element_post_message(GST_ELEMENT(nuv), msg);
renatofilho@754:     }
renatofilho@754: 
renatofilho@754:     GST_DEBUG_OBJECT(nuv,
renatofilho@754:                      "NEW SEGMENT START %" G_GUINT64_FORMAT ", STOP %"
renatofilho@754:                      G_GUINT64_FORMAT, segment_start, segment_stop);
renatofilho@754:     newsegment_event =
renatofilho@754:         gst_event_new_new_segment(FALSE, rate, GST_FORMAT_TIME,
renatofilho@754:                                   segment_start, segment_stop,
renatofilho@754:                                   segment_start);
renatofilho@754: 
renatofilho@754: 
renatofilho@754:     if (flush) {
renatofilho@754:         if (nuv->priv->src_video_pad != NULL) {
renatofilho@754:             gst_pad_push_event(nuv->priv->src_video_pad,
renatofilho@754:                                gst_event_new_flush_stop());
renatofilho@754:         }
renatofilho@754: 
renatofilho@754:         if (nuv->priv->src_audio_pad != NULL) {
renatofilho@754:             gst_pad_push_event(nuv->priv->src_audio_pad,
renatofilho@754:                                gst_event_new_flush_stop());
renatofilho@754:         }
renatofilho@754: 
renatofilho@754:         gst_pad_push_event(nuv->priv->sinkpad, gst_event_new_flush_stop());
renatofilho@754:     }
renatofilho@754: 
renatofilho@754: 
renatofilho@754:     if (nuv->priv->src_video_pad != NULL) {
renatofilho@754:         gst_pad_push_event(nuv->priv->src_video_pad,
renatofilho@754:                            gst_event_ref(newsegment_event));
renatofilho@754:     }
renatofilho@754:     if (nuv->priv->src_audio_pad != NULL) {
renatofilho@754:         gst_pad_push_event(nuv->priv->src_audio_pad,
renatofilho@754:                            gst_event_ref(newsegment_event));
renatofilho@754:     }
renatofilho@754: 
renatofilho@754:     gst_event_unref(newsegment_event);
renatofilho@754: 
renatofilho@754:     nuv->priv->state = GST_NUV_DEMUX_FRAME_HEADER;
renatofilho@754:     nuv->priv->offset = entry->offset;
renatofilho@754: 
renatofilho@754:     gst_pad_start_task(nuv->priv->sinkpad,
renatofilho@754:                        (GstTaskFunction) gst_nuv_demux_loop,
renatofilho@754:                        nuv->priv->sinkpad);
renatofilho@754: 
renatofilho@754:     GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
renatofilho@754:     return TRUE;
renatofilho@754: 
renatofilho@754:   seek_error:
renatofilho@754:     GST_DEBUG_OBJECT(nuv, "Got a seek error");
renatofilho@754:     GST_OBJECT_UNLOCK(nuv);
renatofilho@754:     GST_PAD_STREAM_UNLOCK(nuv->priv->sinkpad);
renatofilho@608:     return FALSE;
renatofilho@608: 
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_srcpad_event(GstPad * pad, GstEvent * event)
renatofilho@608: {
renatofilho@754:     gboolean        res = FALSE;
renatofilho@754:     GstNuvDemux    *nuv;
renatofilho@608: 
renatofilho@754:     nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
renatofilho@751: 
renatofilho@754:     switch (GST_EVENT_TYPE(event)) {
renatofilho@754:     case GST_EVENT_SEEK:
renatofilho@754:         res = gst_nuv_demux_do_seek(nuv, event);
renatofilho@754:         break;
renatofilho@754:     default:
renatofilho@754:         res = FALSE;
renatofilho@754:         break;
renatofilho@754:     }
renatofilho@751: 
renatofilho@754:     gst_object_unref(nuv);
renatofilho@754:     return res;
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: gst_nuv_demux_sink_event(GstPad * pad, GstEvent * event)
renatofilho@714: {
renatofilho@754:     gboolean        res = FALSE;
renatofilho@754:     GstNuvDemux    *nuv;
renatofilho@714: 
renatofilho@754:     nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
renatofilho@714: 
renatofilho@754:     switch (GST_EVENT_TYPE(event)) {
renatofilho@822:         case GST_EVENT_NEWSEGMENT:
renatofilho@754:             GST_PAD_STREAM_LOCK(pad);
renatofilho@754:             gst_nuv_demux_reset(nuv);
renatofilho@754:             GST_PAD_STREAM_UNLOCK(pad);
rosfran@725: 
renatofilho@822:             //res = gst_pad_event_default(pad, event);
renatofilho@822:             res = TRUE;
renatofilho@822:             break;
renatofilho@822:         default:
renatofilho@754:             res = gst_pad_event_default(pad, event);
renatofilho@754:             break;
renatofilho@754:     }
renatofilho@714: 
renatofilho@754:     return res;
renatofilho@714: }
renatofilho@714: 
renatofilho@754: static          GstFlowReturn
renatofilho@751: gst_nuv_demux_chain(GstPad * pad, GstBuffer * buf)
renatofilho@608: {
renatofilho@754:     GstFlowReturn   ret = GST_FLOW_OK;
renatofilho@754:     GstNuvDemux    *nuv = GST_NUV_DEMUX(gst_pad_get_parent(pad));
renatofilho@751: 
renatofilho@754:     if (nuv->priv->mode != NUV_PUSH_MODE)
renatofilho@754:         return ret;
renatofilho@608: 
renatofilho@754:     gst_adapter_push(nuv->priv->adapter, buf);
renatofilho@751: 
renatofilho@754:     while ((ret == GST_FLOW_OK) && (nuv->priv->more_data == FALSE)) {
renatofilho@754:         ret = gst_nuv_demux_play(pad);
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     nuv->priv->more_data = FALSE;
renatofilho@754:     gst_object_unref(nuv);
renatofilho@608: 
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_loop(GstPad * pad)
renatofilho@608: {
renatofilho@754:     gst_nuv_demux_play(pad);
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_index_free(gpointer data, gpointer user_data)
renatofilho@608: {
renatofilho@754:     g_free(data);
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_reset(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     nuv->priv->eos = FALSE;
renatofilho@754:     nuv->priv->more_data = FALSE;
renatofilho@754:     nuv->priv->state = GST_NUV_DEMUX_START;
renatofilho@754:     nuv->priv->mode = NUV_PUSH_MODE;
renatofilho@754:     nuv->priv->offset = 0;
renatofilho@754:     nuv->priv->time_start = 0;
renatofilho@754:     nuv->priv->time_qos = GST_CLOCK_TIME_NONE;
renatofilho@754:     nuv->priv->duration_bytes = GST_CLOCK_TIME_NONE;
renatofilho@754:     nuv->priv->duration_time = GST_CLOCK_TIME_NONE;
renatofilho@754:     nuv->priv->last_video_return = GST_FLOW_OK;
renatofilho@754:     nuv->priv->last_audio_return = GST_FLOW_OK;
renatofilho@754:     nuv->priv->header_lengh = 0;
renatofilho@754:     nuv->priv->segment_stop = GST_CLOCK_TIME_NONE;
renatofilho@754:     nuv->priv->segment_start = GST_CLOCK_TIME_NONE;
renatofilho@754:     nuv->priv->new_file = FALSE;
renatofilho@608: 
renatofilho@754:     // clear index list
renatofilho@754:     g_slist_foreach(nuv->priv->index, gst_nuv_demux_index_free, NULL);
renatofilho@754:     g_slist_free(nuv->priv->index);
renatofilho@754:     nuv->priv->index = NULL;
renatofilho@608: 
renatofilho@754:     gst_adapter_clear(nuv->priv->adapter);
renatofilho@608: 
renatofilho@754:     if (nuv->priv->mpeg_buffer != NULL) {
renatofilho@754:         gst_buffer_unref(nuv->priv->mpeg_buffer);
renatofilho@754:         nuv->priv->mpeg_buffer = NULL;
renatofilho@754:     }
renatofilho@608: }
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_demux_destoy_src_pad(GstNuvDemux * nuv)
renatofilho@608: {
renatofilho@754:     if (nuv->priv->src_video_pad) {
renatofilho@754:         gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_video_pad);
renatofilho@754:         nuv->priv->src_video_pad = NULL;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (nuv->priv->src_audio_pad) {
renatofilho@754:         gst_element_remove_pad(GST_ELEMENT(nuv), nuv->priv->src_audio_pad);
renatofilho@754:         nuv->priv->src_audio_pad = NULL;
renatofilho@754:     }
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          GstStateChangeReturn
renatofilho@751: gst_nuv_demux_change_state(GstElement * element, GstStateChange transition)
renatofilho@608: {
renatofilho@754:     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
renatofilho@608: 
renatofilho@754:     switch (transition) {
renatofilho@754:     case GST_STATE_CHANGE_NULL_TO_READY:
renatofilho@754:         gst_nuv_demux_reset(GST_NUV_DEMUX(element));
renatofilho@754:         gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
renatofilho@754:         break;
renatofilho@754:     default:
renatofilho@754:         break;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     ret =
renatofilho@754:         GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
renatofilho@754:     if (ret == GST_STATE_CHANGE_FAILURE) {
renatofilho@754:         goto done;
renatofilho@754:     }
renatofilho@608: 
renatofilho@692: 
renatofilho@754:     switch (transition) {
renatofilho@754:     case GST_STATE_CHANGE_READY_TO_NULL:
renatofilho@754:         gst_nuv_demux_reset(GST_NUV_DEMUX(element));
renatofilho@754:         gst_nuv_demux_destoy_src_pad(GST_NUV_DEMUX(element));
renatofilho@754:         break;
renatofilho@754:     default:
renatofilho@754:         break;
renatofilho@754:     }
renatofilho@754:   done:
renatofilho@754:     return ret;
renatofilho@608: }
renatofilho@608: 
renatofilho@751: #if (GST_VERSION_MINOR == 10) && (GST_VERSION_MICRO < 6)
renatofilho@754: GstBuffer      *
renatofilho@751: gst_adapter_take_buffer(GstAdapter * adapter, guint nbytes)
renatofilho@608: {
renatofilho@754:     GstBuffer      *buffer;
renatofilho@754:     GstBuffer      *cur;
renatofilho@754:     guint8         *data;
renatofilho@608: 
renatofilho@754:     g_return_val_if_fail(GST_IS_ADAPTER(adapter), NULL);
renatofilho@754:     g_return_val_if_fail(nbytes > 0, NULL);
renatofilho@608: 
renatofilho@754:     GST_LOG_OBJECT(adapter, "taking buffer of %u bytes", nbytes);
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * we don't have enough data, return NULL. This is unlikely as one
renatofilho@754:      * usually does an _available() first instead of peeking a random
renatofilho@754:      * size. 
renatofilho@754:      */
renatofilho@754:     if (G_UNLIKELY(nbytes > adapter->size))
renatofilho@754:         return NULL;
renatofilho@608: 
renatofilho@754:     /*
renatofilho@754:      * our head buffer has enough data left, return it 
renatofilho@754:      */
renatofilho@754:     cur = adapter->buflist->data;
renatofilho@754:     if (GST_BUFFER_SIZE(cur) >= nbytes + adapter->skip) {
renatofilho@754:         GST_LOG_OBJECT(adapter,
renatofilho@754:                        "providing buffer of %d bytes via sub-buffer",
renatofilho@754:                        nbytes);
renatofilho@754:         buffer = gst_buffer_create_sub(cur, adapter->skip, nbytes);
renatofilho@608: 
renatofilho@754:         gst_adapter_flush(adapter, nbytes);
renatofilho@608: 
renatofilho@754:         return buffer;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     data = gst_adapter_take(adapter, nbytes);
renatofilho@754:     if (data == NULL)
renatofilho@754:         return NULL;
renatofilho@608: 
renatofilho@754:     buffer = gst_buffer_new();
renatofilho@754:     GST_BUFFER_DATA(buffer) = data;
renatofilho@754:     GST_BUFFER_MALLOCDATA(buffer) = data;
renatofilho@754:     GST_BUFFER_SIZE(buffer) = nbytes;
renatofilho@608: 
renatofilho@754:     return buffer;
renatofilho@608: }
renatofilho@608: #endif
renatofilho@608: 
renatofilho@608: static void
renatofilho@751: gst_nuv_typefind(GstTypeFind * tf, gpointer unused)
renatofilho@608: {
renatofilho@754:     guint8         *data = gst_type_find_peek(tf, 0, 11);
renatofilho@608: 
renatofilho@754:     if (data) {
renatofilho@754:         if (memcmp(data, "MythTVVideo", 11) == 0
renatofilho@754:             || memcmp(data, "NuppelVideo", 11) == 0) {
renatofilho@754:             gst_type_find_suggest(tf, GST_TYPE_FIND_MAXIMUM,
renatofilho@754:                                   gst_caps_new_simple("video/x-nuv",
renatofilho@754:                                                       NULL));
renatofilho@754:         }
renatofilho@754:     }
renatofilho@608: }
renatofilho@608: 
renatofilho@754: static          gboolean
renatofilho@751: plugin_init(GstPlugin * plugin)
renatofilho@608: {
renatofilho@754:     static gchar   *exts[] = { "nuv", NULL };
renatofilho@608: #ifdef ENABLE_NLS
renatofilho@754:     setlocale(LC_ALL, "");
renatofilho@754:     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
renatofilho@754: #endif                          /* ENABLE_NLS */
renatofilho@608: 
renatofilho@754:     if (!gst_element_register(plugin, "nuvdemux", GST_RANK_SECONDARY,
renatofilho@754:                               GST_TYPE_NUV_DEMUX)) {
renatofilho@754:         return FALSE;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     if (!gst_type_find_register(plugin, "video/x-nuv", GST_RANK_SECONDARY,
renatofilho@754:                                 gst_nuv_typefind,
renatofilho@754:                                 exts,
renatofilho@754:                                 gst_caps_new_simple("video/x-nuv", NULL),
renatofilho@754:                                 NULL, NULL)) {
renatofilho@754:         GST_WARNING("can't register typefind");
renatofilho@754:         return FALSE;
renatofilho@754:     }
renatofilho@608: 
renatofilho@754:     return TRUE;
renatofilho@608: }
renatofilho@608: 
renatofilho@751: GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
renatofilho@754:                   GST_VERSION_MINOR,
renatofilho@754:                   "nuvdemux",
renatofilho@754:                   "Demuxes and muxes audio and video",
renatofilho@754:                   plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
renatofilho@754:                   GST_PACKAGE_ORIGIN)