[longomatch/encoder: 1/2] libcesarplayer: add a multifile re-encoder



commit ff319a3cdd51bc1684a8f58f9c7860a1c96cce98
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date:   Fri Mar 8 16:19:54 2013 +0100

    libcesarplayer: add a multifile re-encoder

 LongoMatch.GUI.Multimedia/VideoConverterTool.cs    |   30 +
 .../gtk-gui/longomatch.VideoConverterTool.cs       |    9 +
 .../LongoMatch.Gui.Dialog.VideoConverterTool.cs    |  275 +++++++
 libcesarplayer/Makefile.am                         |    5 +
 libcesarplayer/gst-video-encoder.c                 |  762 ++++++++++++++++++++
 libcesarplayer/gst-video-encoder.h                 |   92 +++
 libcesarplayer/test-encoder.c                      |   93 +++
 7 files changed, 1266 insertions(+), 0 deletions(-)
---
diff --git a/LongoMatch.GUI.Multimedia/VideoConverterTool.cs b/LongoMatch.GUI.Multimedia/VideoConverterTool.cs
new file mode 100644
index 0000000..d820ad9
--- /dev/null
+++ b/LongoMatch.GUI.Multimedia/VideoConverterTool.cs
@@ -0,0 +1,30 @@
+// 
+//  Copyright (C) 2013 Andoni Morales Alastruey
+// 
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+// 
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//  GNU General Public License for more details.
+//  
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+// 
+using System;
+
+namespace longomatch
+{
+       public partial class VideoConverterTool : Gtk.Dialog
+       {
+               public VideoConverterTool ()
+               {
+                       this.Build ();
+               }
+       }
+}
+
diff --git a/LongoMatch.GUI.Multimedia/gtk-gui/longomatch.VideoConverterTool.cs 
b/LongoMatch.GUI.Multimedia/gtk-gui/longomatch.VideoConverterTool.cs
new file mode 100644
index 0000000..80bf7e9
--- /dev/null
+++ b/LongoMatch.GUI.Multimedia/gtk-gui/longomatch.VideoConverterTool.cs
@@ -0,0 +1,9 @@
+
+namespace longomatch
+{
+       public partial class VideoConverterTool
+       {
+               private Gtk.Button buttonCancel;
+               private Gtk.Button buttonOk;
+       }
+}
diff --git a/LongoMatch.GUI/gtk-gui/LongoMatch.Gui.Dialog.VideoConverterTool.cs 
b/LongoMatch.GUI/gtk-gui/LongoMatch.Gui.Dialog.VideoConverterTool.cs
new file mode 100644
index 0000000..cf42d65
--- /dev/null
+++ b/LongoMatch.GUI/gtk-gui/LongoMatch.Gui.Dialog.VideoConverterTool.cs
@@ -0,0 +1,275 @@
+
+// This file has been generated by the GUI designer. Do not modify.
+namespace LongoMatch.Gui.Dialog
+{
+       public partial class VideoConverterTool
+       {
+               private global::Gtk.VBox vbox3;
+               private global::Gtk.HBox hbox2;
+               private global::Gtk.ScrolledWindow GtkScrolledWindow;
+               private global::Gtk.NodeView filesview;
+               private global::Gtk.VBox vbox4;
+               private global::Gtk.Button addbutton;
+               private global::Gtk.Button removebutton;
+               private global::Gtk.VBox vbox2;
+               private global::Gtk.HBox hbox3;
+               private global::Gtk.Label label1;
+               private global::Gtk.ComboBox qualitycombobox;
+               private global::Gtk.HBox hbox4;
+               private global::Gtk.Label label2;
+               private global::Gtk.ComboBox sizecombobox;
+               private global::Gtk.HBox hbox5;
+               private global::Gtk.Label label3;
+               private global::Gtk.ComboBox formatcombobox;
+               private global::Gtk.HBox filebox;
+               private global::Gtk.Label filenamelabel;
+               private global::Gtk.HBox hbox7;
+               private global::Gtk.Label filelabel;
+               private global::Gtk.Button openbutton;
+               private global::Gtk.Button buttonCancel;
+               private global::Gtk.Button buttonOk;
+               
+               protected virtual void Build ()
+               {
+                       global::Stetic.Gui.Initialize (this);
+                       // Widget LongoMatch.Gui.Dialog.VideoConverterTool
+                       this.Name = "LongoMatch.Gui.Dialog.VideoConverterTool";
+                       this.Title = global::Mono.Unix.Catalog.GetString ("Video Converter Tool");
+                       this.WindowPosition = ((global::Gtk.WindowPosition)(4));
+                       this.Modal = true;
+                       this.Gravity = ((global::Gdk.Gravity)(5));
+                       this.SkipPagerHint = true;
+                       this.SkipTaskbarHint = true;
+                       // Internal child LongoMatch.Gui.Dialog.VideoConverterTool.VBox
+                       global::Gtk.VBox w1 = this.VBox;
+                       w1.Name = "dialog1_VBox";
+                       w1.BorderWidth = ((uint)(2));
+                       // Container child dialog1_VBox.Gtk.Box+BoxChild
+                       this.vbox3 = new global::Gtk.VBox ();
+                       this.vbox3.Name = "vbox3";
+                       this.vbox3.Spacing = 6;
+                       // Container child vbox3.Gtk.Box+BoxChild
+                       this.hbox2 = new global::Gtk.HBox ();
+                       this.hbox2.Name = "hbox2";
+                       this.hbox2.Spacing = 6;
+                       // Container child hbox2.Gtk.Box+BoxChild
+                       this.GtkScrolledWindow = new global::Gtk.ScrolledWindow ();
+                       this.GtkScrolledWindow.Name = "GtkScrolledWindow";
+                       this.GtkScrolledWindow.ShadowType = ((global::Gtk.ShadowType)(1));
+                       // Container child GtkScrolledWindow.Gtk.Container+ContainerChild
+                       this.filesview = new global::Gtk.NodeView ();
+                       this.filesview.CanFocus = true;
+                       this.filesview.Name = "filesview";
+                       this.GtkScrolledWindow.Add (this.filesview);
+                       this.hbox2.Add (this.GtkScrolledWindow);
+                       global::Gtk.Box.BoxChild w3 = ((global::Gtk.Box.BoxChild)(this.hbox2 
[this.GtkScrolledWindow]));
+                       w3.Position = 0;
+                       // Container child hbox2.Gtk.Box+BoxChild
+                       this.vbox4 = new global::Gtk.VBox ();
+                       this.vbox4.Name = "vbox4";
+                       this.vbox4.Spacing = 6;
+                       // Container child vbox4.Gtk.Box+BoxChild
+                       this.addbutton = new global::Gtk.Button ();
+                       this.addbutton.CanFocus = true;
+                       this.addbutton.Name = "addbutton";
+                       this.addbutton.UseStock = true;
+                       this.addbutton.UseUnderline = true;
+                       this.addbutton.Label = "gtk-add";
+                       this.vbox4.Add (this.addbutton);
+                       global::Gtk.Box.BoxChild w4 = ((global::Gtk.Box.BoxChild)(this.vbox4 
[this.addbutton]));
+                       w4.Position = 0;
+                       w4.Expand = false;
+                       w4.Fill = false;
+                       // Container child vbox4.Gtk.Box+BoxChild
+                       this.removebutton = new global::Gtk.Button ();
+                       this.removebutton.CanFocus = true;
+                       this.removebutton.Name = "removebutton";
+                       this.removebutton.UseStock = true;
+                       this.removebutton.UseUnderline = true;
+                       this.removebutton.Label = "gtk-remove";
+                       this.vbox4.Add (this.removebutton);
+                       global::Gtk.Box.BoxChild w5 = ((global::Gtk.Box.BoxChild)(this.vbox4 
[this.removebutton]));
+                       w5.Position = 1;
+                       w5.Expand = false;
+                       w5.Fill = false;
+                       this.hbox2.Add (this.vbox4);
+                       global::Gtk.Box.BoxChild w6 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.vbox4]));
+                       w6.Position = 1;
+                       w6.Expand = false;
+                       this.vbox3.Add (this.hbox2);
+                       global::Gtk.Box.BoxChild w7 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.hbox2]));
+                       w7.Position = 0;
+                       // Container child vbox3.Gtk.Box+BoxChild
+                       this.vbox2 = new global::Gtk.VBox ();
+                       this.vbox2.Name = "vbox2";
+                       this.vbox2.Spacing = 6;
+                       // Container child vbox2.Gtk.Box+BoxChild
+                       this.hbox3 = new global::Gtk.HBox ();
+                       this.hbox3.Name = "hbox3";
+                       this.hbox3.Homogeneous = true;
+                       this.hbox3.Spacing = 6;
+                       // Container child hbox3.Gtk.Box+BoxChild
+                       this.label1 = new global::Gtk.Label ();
+                       this.label1.Name = "label1";
+                       this.label1.Xalign = 0F;
+                       this.label1.LabelProp = global::Mono.Unix.Catalog.GetString ("Video Quality:");
+                       this.hbox3.Add (this.label1);
+                       global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.label1]));
+                       w8.Position = 0;
+                       // Container child hbox3.Gtk.Box+BoxChild
+                       this.qualitycombobox = global::Gtk.ComboBox.NewText ();
+                       this.qualitycombobox.AppendText (global::Mono.Unix.Catalog.GetString ("Low"));
+                       this.qualitycombobox.AppendText (global::Mono.Unix.Catalog.GetString ("Normal"));
+                       this.qualitycombobox.AppendText (global::Mono.Unix.Catalog.GetString ("Good"));
+                       this.qualitycombobox.AppendText (global::Mono.Unix.Catalog.GetString ("Extra"));
+                       this.qualitycombobox.Name = "qualitycombobox";
+                       this.qualitycombobox.Active = 1;
+                       this.hbox3.Add (this.qualitycombobox);
+                       global::Gtk.Box.BoxChild w9 = ((global::Gtk.Box.BoxChild)(this.hbox3 
[this.qualitycombobox]));
+                       w9.Position = 1;
+                       this.vbox2.Add (this.hbox3);
+                       global::Gtk.Box.BoxChild w10 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox3]));
+                       w10.Position = 0;
+                       w10.Expand = false;
+                       w10.Fill = false;
+                       // Container child vbox2.Gtk.Box+BoxChild
+                       this.hbox4 = new global::Gtk.HBox ();
+                       this.hbox4.Name = "hbox4";
+                       this.hbox4.Homogeneous = true;
+                       this.hbox4.Spacing = 6;
+                       // Container child hbox4.Gtk.Box+BoxChild
+                       this.label2 = new global::Gtk.Label ();
+                       this.label2.Name = "label2";
+                       this.label2.Xalign = 0F;
+                       this.label2.LabelProp = global::Mono.Unix.Catalog.GetString ("Size: ");
+                       this.hbox4.Add (this.label2);
+                       global::Gtk.Box.BoxChild w11 = ((global::Gtk.Box.BoxChild)(this.hbox4 [this.label2]));
+                       w11.Position = 0;
+                       // Container child hbox4.Gtk.Box+BoxChild
+                       this.sizecombobox = global::Gtk.ComboBox.NewText ();
+                       this.sizecombobox.Name = "sizecombobox";
+                       this.hbox4.Add (this.sizecombobox);
+                       global::Gtk.Box.BoxChild w12 = ((global::Gtk.Box.BoxChild)(this.hbox4 
[this.sizecombobox]));
+                       w12.Position = 1;
+                       this.vbox2.Add (this.hbox4);
+                       global::Gtk.Box.BoxChild w13 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox4]));
+                       w13.Position = 1;
+                       w13.Expand = false;
+                       w13.Fill = false;
+                       // Container child vbox2.Gtk.Box+BoxChild
+                       this.hbox5 = new global::Gtk.HBox ();
+                       this.hbox5.Name = "hbox5";
+                       this.hbox5.Homogeneous = true;
+                       this.hbox5.Spacing = 6;
+                       // Container child hbox5.Gtk.Box+BoxChild
+                       this.label3 = new global::Gtk.Label ();
+                       this.label3.Name = "label3";
+                       this.label3.Xalign = 0F;
+                       this.label3.LabelProp = global::Mono.Unix.Catalog.GetString ("Ouput Format:");
+                       this.hbox5.Add (this.label3);
+                       global::Gtk.Box.BoxChild w14 = ((global::Gtk.Box.BoxChild)(this.hbox5 [this.label3]));
+                       w14.Position = 0;
+                       // Container child hbox5.Gtk.Box+BoxChild
+                       this.formatcombobox = global::Gtk.ComboBox.NewText ();
+                       this.formatcombobox.Name = "formatcombobox";
+                       this.hbox5.Add (this.formatcombobox);
+                       global::Gtk.Box.BoxChild w15 = ((global::Gtk.Box.BoxChild)(this.hbox5 
[this.formatcombobox]));
+                       w15.Position = 1;
+                       this.vbox2.Add (this.hbox5);
+                       global::Gtk.Box.BoxChild w16 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox5]));
+                       w16.Position = 2;
+                       w16.Expand = false;
+                       w16.Fill = false;
+                       // Container child vbox2.Gtk.Box+BoxChild
+                       this.filebox = new global::Gtk.HBox ();
+                       this.filebox.Name = "filebox";
+                       this.filebox.Spacing = 6;
+                       // Container child filebox.Gtk.Box+BoxChild
+                       this.filenamelabel = new global::Gtk.Label ();
+                       this.filenamelabel.Name = "filenamelabel";
+                       this.filenamelabel.LabelProp = global::Mono.Unix.Catalog.GetString ("File name: ");
+                       this.filebox.Add (this.filenamelabel);
+                       global::Gtk.Box.BoxChild w17 = ((global::Gtk.Box.BoxChild)(this.filebox 
[this.filenamelabel]));
+                       w17.Position = 0;
+                       w17.Expand = false;
+                       w17.Fill = false;
+                       // Container child filebox.Gtk.Box+BoxChild
+                       this.hbox7 = new global::Gtk.HBox ();
+                       this.hbox7.Name = "hbox7";
+                       this.hbox7.Spacing = 6;
+                       // Container child hbox7.Gtk.Box+BoxChild
+                       this.filelabel = new global::Gtk.Label ();
+                       this.filelabel.Name = "filelabel";
+                       this.hbox7.Add (this.filelabel);
+                       global::Gtk.Box.BoxChild w18 = ((global::Gtk.Box.BoxChild)(this.hbox7 
[this.filelabel]));
+                       w18.Position = 0;
+                       // Container child hbox7.Gtk.Box+BoxChild
+                       this.openbutton = new global::Gtk.Button ();
+                       this.openbutton.CanFocus = true;
+                       this.openbutton.Name = "openbutton";
+                       this.openbutton.UseStock = true;
+                       this.openbutton.UseUnderline = true;
+                       this.openbutton.Label = "gtk-save-as";
+                       this.hbox7.Add (this.openbutton);
+                       global::Gtk.Box.BoxChild w19 = ((global::Gtk.Box.BoxChild)(this.hbox7 
[this.openbutton]));
+                       w19.Position = 1;
+                       w19.Expand = false;
+                       w19.Fill = false;
+                       this.filebox.Add (this.hbox7);
+                       global::Gtk.Box.BoxChild w20 = ((global::Gtk.Box.BoxChild)(this.filebox 
[this.hbox7]));
+                       w20.Position = 1;
+                       this.vbox2.Add (this.filebox);
+                       global::Gtk.Box.BoxChild w21 = ((global::Gtk.Box.BoxChild)(this.vbox2 
[this.filebox]));
+                       w21.Position = 3;
+                       w21.Expand = false;
+                       w21.Fill = false;
+                       this.vbox3.Add (this.vbox2);
+                       global::Gtk.Box.BoxChild w22 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.vbox2]));
+                       w22.Position = 1;
+                       w22.Expand = false;
+                       w22.Fill = false;
+                       w1.Add (this.vbox3);
+                       global::Gtk.Box.BoxChild w23 = ((global::Gtk.Box.BoxChild)(w1 [this.vbox3]));
+                       w23.Position = 0;
+                       // Internal child LongoMatch.Gui.Dialog.VideoConverterTool.ActionArea
+                       global::Gtk.HButtonBox w24 = this.ActionArea;
+                       w24.Name = "dialog1_ActionArea";
+                       w24.Spacing = 10;
+                       w24.BorderWidth = ((uint)(5));
+                       w24.LayoutStyle = ((global::Gtk.ButtonBoxStyle)(4));
+                       // Container child dialog1_ActionArea.Gtk.ButtonBox+ButtonBoxChild
+                       this.buttonCancel = new global::Gtk.Button ();
+                       this.buttonCancel.CanDefault = true;
+                       this.buttonCancel.CanFocus = true;
+                       this.buttonCancel.Name = "buttonCancel";
+                       this.buttonCancel.UseStock = true;
+                       this.buttonCancel.UseUnderline = true;
+                       this.buttonCancel.Label = "gtk-cancel";
+                       this.AddActionWidget (this.buttonCancel, -6);
+                       global::Gtk.ButtonBox.ButtonBoxChild w25 = 
((global::Gtk.ButtonBox.ButtonBoxChild)(w24 [this.buttonCancel]));
+                       w25.Expand = false;
+                       w25.Fill = false;
+                       // Container child dialog1_ActionArea.Gtk.ButtonBox+ButtonBoxChild
+                       this.buttonOk = new global::Gtk.Button ();
+                       this.buttonOk.CanDefault = true;
+                       this.buttonOk.CanFocus = true;
+                       this.buttonOk.Name = "buttonOk";
+                       this.buttonOk.UseStock = true;
+                       this.buttonOk.UseUnderline = true;
+                       this.buttonOk.Label = "gtk-ok";
+                       this.AddActionWidget (this.buttonOk, -5);
+                       global::Gtk.ButtonBox.ButtonBoxChild w26 = 
((global::Gtk.ButtonBox.ButtonBoxChild)(w24 [this.buttonOk]));
+                       w26.Position = 1;
+                       w26.Expand = false;
+                       w26.Fill = false;
+                       if ((this.Child != null)) {
+                               this.Child.ShowAll ();
+                       }
+                       this.DefaultWidth = 400;
+                       this.DefaultHeight = 463;
+                       this.Show ();
+                       this.addbutton.Clicked += new global::System.EventHandler (this.OnAddbuttonClicked);
+                       this.removebutton.Clicked += new global::System.EventHandler 
(this.OnRemovebuttonClicked);
+               }
+       }
+}
diff --git a/libcesarplayer/Makefile.am b/libcesarplayer/Makefile.am
index 4ab9dfd..4c383c8 100644
--- a/libcesarplayer/Makefile.am
+++ b/libcesarplayer/Makefile.am
@@ -41,6 +41,8 @@ libcesarplayer_la_SOURCES = \
        gst-remuxer.h\
        gst-video-editor.c\
        gst-video-editor.h\
+       gst-video-encoder.c\
+       gst-video-encoder.h\
        video-utils.c\
        video-utils.h\
        macros.h
@@ -57,3 +59,6 @@ CLEANFILES = $(BUILT_SOURCES)
 EXTRA_DIST = \
        baconvideowidget-marshal.list
 
+
+test-encoder: test-encoder.c gst-video-encoder.c
+       ${CC} -o test-encoder test-encoder.c gst-video-encoder.c $(CESARPLAYER_CFLAGS) $(CESARPLAYER_LIBS) 
-O0 -g
diff --git a/libcesarplayer/gst-video-encoder.c b/libcesarplayer/gst-video-encoder.c
new file mode 100644
index 0000000..cca887c
--- /dev/null
+++ b/libcesarplayer/gst-video-encoder.c
@@ -0,0 +1,762 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+* Gstreamer Video Encoder
+* Copyright (C)  Andoni Morales Alastruey 2013 <ylatuya gmail com>
+*
+* You may redistribute it and/or modify it under the terms of the
+* GNU General Public License, as published by the Free Software
+* Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* Gstreamer DV is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with foob.  If not, write to:
+*       The Free Software Foundation, Inc.,
+*       51 Franklin Street, Fifth Floor
+*       Boston, MA  02110-1301, USA.
+*/
+
+#include <gst/gst.h>
+#include <gtk/gtk.h>
+
+#include "gst-video-encoder.h"
+
+
+GST_DEBUG_CATEGORY (_video_encoder_gst_debug_cat);
+#define GST_CAT_DEFAULT _video_encoder_gst_debug_cat
+
+/* Signals */
+enum
+{
+  SIGNAL_ERROR,
+  SIGNAL_PERCENT_COMPLETED,
+  LAST_SIGNAL
+};
+
+struct GstVideoEncoderPrivate
+{
+
+  /*Encoding properties */
+  gchar *output_file;
+  GList *input_files;
+  GList *current_file;
+  guint output_height;
+  guint output_width;
+  guint audio_bitrate;
+  guint video_bitrate;
+  guint fps_n;
+  guint fps_d;
+  VideoEncoderType video_encoder_type;
+  AudioEncoderType audio_encoder_type;
+  VideoMuxerType video_muxer_type;
+
+  /*GStreamer elements */
+  GstElement *main_pipeline;
+  GstElement *source_bin;
+  GstElement *encoder_bin;
+  GstElement *video_enc;
+  GstElement *audio_enc;
+  GstElement *muxer;
+  GstElement *filesink;
+
+  /*GStreamer bus */
+  GstBus *bus;
+  gulong sig_bus_async;
+
+  gboolean drained;
+};
+
+static GObjectClass *parent_class = NULL;
+
+static int gve_signals[LAST_SIGNAL] = { 0 };
+
+static void gve_error_msg (GstVideoEncoder * gcc, GstMessage * msg);
+static void gve_bus_message_cb (GstBus * bus, GstMessage * message,
+    gpointer data);
+static gboolean gst_video_encoder_select_next_file (GstVideoEncoder *gve);
+
+G_DEFINE_TYPE (GstVideoEncoder, gst_video_encoder, G_TYPE_OBJECT);
+
+/***********************************
+*
+*     Class, Object and Properties
+*
+************************************/
+
+static void
+gst_video_encoder_init (GstVideoEncoder * object)
+{
+  GstVideoEncoderPrivate *priv;
+  object->priv = priv =
+      G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_VIDEO_ENCODER,
+      GstVideoEncoderPrivate);
+
+  priv->output_height = 480;
+  priv->output_width = 640;
+  priv->audio_bitrate = 128;
+  priv->video_bitrate = 5000;
+  priv->video_encoder_type = VIDEO_ENCODER_VP8;
+  priv->audio_encoder_type = AUDIO_ENCODER_VORBIS;
+  priv->video_muxer_type = VIDEO_MUXER_WEBM;
+}
+
+void
+gst_video_encoder_finalize (GObject * object)
+{
+  GstVideoEncoder *gve = (GstVideoEncoder *) object;
+
+  GST_DEBUG_OBJECT (gve, "Finalizing.");
+  if (gve->priv->bus) {
+    /* make bus drop all messages to make sure none of our callbacks is ever
+     * called again (main loop might be run again to display error dialog) */
+    gst_bus_set_flushing (gve->priv->bus, TRUE);
+
+    if (gve->priv->sig_bus_async)
+      g_signal_handler_disconnect (gve->priv->bus, gve->priv->sig_bus_async);
+
+    gst_object_unref (gve->priv->bus);
+    gve->priv->bus = NULL;
+  }
+
+  if (gve->priv->output_file) {
+    g_free (gve->priv->output_file);
+    gve->priv->output_file = NULL;
+  }
+
+  if (gve->priv->input_files) {
+    g_list_foreach (gve->priv->input_files, (GFunc) g_free, NULL);
+    g_free (gve->priv->input_files);
+    gve->priv->input_files = NULL;
+  }
+
+  if (gve->priv->main_pipeline != NULL
+      && GST_IS_ELEMENT (gve->priv->main_pipeline)) {
+    gst_element_set_state (gve->priv->main_pipeline, GST_STATE_NULL);
+    gst_object_unref (gve->priv->main_pipeline);
+    gve->priv->main_pipeline = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_video_encoder_class_init (GstVideoEncoderClass * klass)
+{
+  GObjectClass *object_class;
+
+  object_class = (GObjectClass *) klass;
+  parent_class = g_type_class_peek_parent (klass);
+
+  g_type_class_add_private (object_class, sizeof (GstVideoEncoderPrivate));
+
+  /* GObject */
+  object_class->finalize = gst_video_encoder_finalize;
+
+  /* Signals */
+  gve_signals[SIGNAL_ERROR] =
+      g_signal_new ("error",
+      G_TYPE_FROM_CLASS (object_class),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstVideoEncoderClass, error),
+      NULL, NULL,
+      g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  gve_signals[SIGNAL_PERCENT_COMPLETED] =
+      g_signal_new ("percent_completed",
+      G_TYPE_FROM_CLASS (object_class),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstVideoEncoderClass, percent_completed),
+      NULL, NULL, g_cclosure_marshal_VOID__FLOAT, G_TYPE_NONE, 1, G_TYPE_FLOAT);
+}
+
+/***********************************
+*
+*           GStreamer
+*
+************************************/
+
+void
+gst_video_encoder_init_backend (int *argc, char ***argv)
+{
+  gst_init (argc, argv);
+}
+
+GQuark
+gst_video_encoder_error_quark (void)
+{
+  static GQuark q;              /* 0 */
+
+  if (G_UNLIKELY (q == 0)) {
+    q = g_quark_from_static_string ("gve-error-quark");
+  }
+  return q;
+}
+
+static void
+gst_video_encoder_create_encoder_bin (GstVideoEncoder *gve)
+{
+  GstElement *colorspace1, *videoscale, *framerate, *deinterlace;
+  GstElement *colorspace2, *audioconvert, *audioresample;
+  GstElement *aqueue, *vqueue;
+  GstElement *v_identity, *a_identity;
+  GstCaps *video_caps, *h264_caps;
+  GstPad *v_sink_pad, *a_sink_pad;
+
+  GST_INFO_OBJECT (gve, "Creating encoder bin");
+  gve->priv->encoder_bin = gst_bin_new ("encoder_bin");
+
+  colorspace1 = gst_element_factory_make("ffmpegcolorspace", NULL);
+  deinterlace = gst_element_factory_make("ffdeinterlace", NULL);
+  colorspace2 = gst_element_factory_make("ffmpegcolorspace", "colorspace2");
+  videoscale = gst_element_factory_make("videoscale", "gve_videoscale");
+  framerate = gst_element_factory_make("videorate", "gve_videorate");
+  audioconvert = gst_element_factory_make("audioconvert", NULL);
+  audioresample = gst_element_factory_make("audioresample", NULL);
+  gve->priv->filesink = gst_element_factory_make("filesink", NULL);
+  aqueue = gst_element_factory_make ("queue", "audio_queue");
+  vqueue = gst_element_factory_make ("queue", "video_queue");
+  a_identity = gst_element_factory_make ("identity", "audio_identity");
+  v_identity = gst_element_factory_make ("identity", "video_identity");
+
+
+  /* Increase audio queue size for h264 encoding as the encoder queues 2 seconds
+   * of video */
+  g_object_set (aqueue, "max-size-time", 5 * GST_SECOND, NULL);
+
+  /* Set caps for the encoding resolution */
+  video_caps = gst_caps_new_simple ("video/x-raw-yuv", NULL);
+  gst_caps_set_simple (video_caps, "format", GST_TYPE_FOURCC,
+      GST_STR_FOURCC ("I420"), NULL);
+  if (gve->priv->output_width != 0) {
+    gst_caps_set_simple (video_caps, "width", G_TYPE_INT, gve->priv->output_width,
+        NULL);
+  }
+  if (gve->priv->output_height != 0) {
+    gst_caps_set_simple (video_caps, "height", G_TYPE_INT, gve->priv->output_height,
+        NULL);
+  }
+
+  /* Set caps for the encoding framerate */
+  if (gve->priv->fps_n != 0 && gve->priv->fps_d != 0) {
+   gst_caps_set_simple (video_caps, "framerate", GST_TYPE_FRACTION,
+      gve->priv->fps_n, gve->priv->fps_d, NULL);
+  }
+
+  /* Set caps for the h264 profile */
+  h264_caps = gst_caps_new_simple ("video/x-h264", NULL);
+  gst_caps_set_simple (h264_caps, "profile", G_TYPE_STRING,
+      "constrained-baseline", "stream-format", G_TYPE_STRING, "avc", NULL);
+
+  g_object_set (a_identity, "single-segment", TRUE, NULL);
+  g_object_set (v_identity, "single-segment", TRUE, NULL);
+
+  gst_bin_add_many(GST_BIN(gve->priv->encoder_bin), v_identity,  colorspace1,
+      deinterlace, videoscale, framerate, colorspace2,
+      vqueue, gve->priv->video_enc, gve->priv->muxer, gve->priv->filesink,
+      a_identity, audioconvert, audioresample, gve->priv->audio_enc, aqueue, NULL);
+
+  gst_element_link_many(v_identity, colorspace1, deinterlace, framerate,
+      videoscale, colorspace2, NULL);
+  gst_element_link_filtered (colorspace2, gve->priv->video_enc, video_caps);
+  gst_element_link_filtered (gve->priv->video_enc, vqueue, h264_caps);
+  gst_element_link (vqueue, gve->priv->muxer);
+  gst_element_link_many(a_identity, audioconvert, audioresample, gve->priv->audio_enc,
+      aqueue, gve->priv->muxer, NULL);
+  gst_element_link(gve->priv->muxer, gve->priv->filesink);
+
+  gst_caps_unref(video_caps);
+  gst_caps_unref (h264_caps);
+  g_object_set (gve->priv->filesink, "location", gve->priv->output_file, NULL);
+
+  /* Create ghost pads */
+  v_sink_pad = gst_element_get_static_pad (v_identity, "sink");
+  a_sink_pad = gst_element_get_static_pad (a_identity, "sink");
+  gst_element_add_pad (gve->priv->encoder_bin,
+      gst_ghost_pad_new ("video", v_sink_pad));
+  gst_element_add_pad (gve->priv->encoder_bin,
+      gst_ghost_pad_new ("audio", a_sink_pad));
+  gst_object_unref (GST_OBJECT (v_sink_pad));
+  gst_object_unref (GST_OBJECT (a_sink_pad));
+
+  gst_bin_add (GST_BIN (gve->priv->main_pipeline), gve->priv->encoder_bin);
+  GST_INFO_OBJECT (gve, "Encoder bin created successfully");
+}
+
+static gboolean
+cb_handle_eos (GstPad *pad, GstEvent *event, GstVideoEncoder *gve)
+{
+  if (event->type == GST_EVENT_EOS) {
+    GST_DEBUG_OBJECT (gve, "Dropping EOS on pad %s:%s",
+        GST_DEBUG_PAD_NAME (pad));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+static void
+cb_new_pad (GstElement *decodebin, GstPad *pad, GstVideoEncoder *gve)
+{
+  GstPad *epad = NULL;
+  GstCaps *caps;
+  const GstStructure *s;
+  const gchar *mime;
+
+  caps = gst_pad_get_caps_reffed (pad);
+  s = gst_caps_get_structure (caps, 0);
+  mime = gst_structure_get_name (s);
+
+  if (g_strrstr (mime, "video")) {
+    epad = gst_element_get_static_pad (gve->priv->encoder_bin, "video");
+  } else if (g_strrstr (mime, "audio")) {
+    epad = gst_element_get_static_pad (gve->priv->encoder_bin, "audio");
+  }
+
+  if (epad && !gst_pad_is_linked (epad)) {
+    GST_INFO_OBJECT (gve, "Linking pad with caps %" GST_PTR_FORMAT, caps);
+    if (gst_pad_link (pad, epad)) {
+      g_signal_emit (gve, gve_signals[SIGNAL_ERROR], 0, "Error linking pads");
+    } else {
+      gst_pad_add_event_probe (pad, G_CALLBACK (cb_handle_eos), gve);
+    }
+  } else {
+    GST_INFO_OBJECT (gve, "Dropping pad with caps %" GST_PTR_FORMAT, caps);
+  }
+  gst_caps_unref (caps);
+}
+
+static void
+cb_drained (GstElement *decodebin, GstVideoEncoder *gve) {
+  if (!gve->priv->drained) {
+    g_idle_add ((GSourceFunc)gst_video_encoder_select_next_file, gve);
+  }
+  gve->priv->drained = TRUE;
+}
+
+static void
+gst_video_encoder_create_source (GstVideoEncoder *gve, gchar *location)
+{
+  GST_INFO_OBJECT (gve, "Creating source");
+
+  if (gve->priv->source_bin != NULL) {
+    gst_element_set_state (gve->priv->source_bin, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN(gve->priv->main_pipeline), gve->priv->source_bin);
+  }
+  gve->priv->source_bin = gst_element_factory_make ("uridecodebin", NULL);
+  g_object_set (gve->priv->source_bin, "uri", location, NULL);
+  g_signal_connect (gve->priv->source_bin, "pad-added", G_CALLBACK (cb_new_pad), gve);
+  g_signal_connect (gve->priv->source_bin, "drained", G_CALLBACK (cb_drained), gve);
+  gst_bin_add (GST_BIN(gve->priv->main_pipeline), gve->priv->source_bin);
+  gst_element_sync_state_with_parent (gve->priv->source_bin);
+  gve->priv->drained = FALSE;
+}
+
+static gboolean
+gst_video_encoder_select_next_file (GstVideoEncoder *gve)
+{
+  GstPad *audio_pad, *video_pad;
+
+  audio_pad = gst_element_get_static_pad (gve->priv->encoder_bin, "audio");
+  video_pad = gst_element_get_static_pad (gve->priv->encoder_bin, "video");
+
+  if (gve->priv->current_file == NULL) {
+    gve->priv->current_file = gve->priv->input_files;
+  } else {
+    gve->priv->current_file = g_list_next (gve->priv->current_file);
+  }
+
+  if (gve->priv->current_file != NULL) {
+    GstPad *a_peer, *v_peer;
+
+    GST_INFO_OBJECT (gve, "Selecting next file: %s",
+        (gchar *) gve->priv->current_file->data);
+    a_peer = gst_pad_get_peer (audio_pad);
+    if (a_peer) {
+      gst_pad_unlink (a_peer, audio_pad);
+      gst_object_unref (a_peer);
+    }
+
+    v_peer = gst_pad_get_peer (video_pad);
+    if (v_peer) {
+      gst_pad_unlink (v_peer, video_pad);
+      gst_object_unref (v_peer);
+    }
+    gst_video_encoder_create_source (gve, (gchar *) gve->priv->current_file->data);
+  } else {
+    GST_INFO_OBJECT (gve, "No more files, sending EOS");
+    gst_pad_send_event (audio_pad, gst_event_new_eos());
+    gst_pad_send_event (video_pad, gst_event_new_eos());
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_video_encoder_create_video_encoder (GstVideoEncoder * gve,
+    VideoEncoderType type, GError ** err)
+{
+  gchar *name = NULL;
+
+  g_return_val_if_fail (gve != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_VIDEO_ENCODER (gve), FALSE);
+
+  switch (type) {
+    case VIDEO_ENCODER_MPEG4:
+      gve->priv->video_enc =
+          gst_element_factory_make ("ffenc_mpeg4", "video-encoder");
+      g_object_set (gve->priv->video_enc, "pass", 512,
+          "max-key-interval", -1, NULL);
+      name = "FFmpeg mpeg4 video encoder";
+      break;
+
+    case VIDEO_ENCODER_XVID:
+      gve->priv->video_enc =
+          gst_element_factory_make ("xvidenc", "video-encoder");
+      g_object_set (gve->priv->video_enc, "pass", 1,
+          "profile", 146, "max-key-interval", -1, NULL);
+      name = "Xvid video encoder";
+      break;
+
+    case VIDEO_ENCODER_H264:
+      gve->priv->video_enc =
+          gst_element_factory_make ("x264enc", "video-encoder");
+      g_object_set (gve->priv->video_enc, "key-int-max", 25, "pass", 17,
+          "speed-preset", 3, NULL);
+      name = "X264 video encoder";
+      break;
+
+    case VIDEO_ENCODER_THEORA:
+      gve->priv->video_enc =
+          gst_element_factory_make ("theoraenc", "video-encoder");
+      g_object_set (gve->priv->video_enc, "keyframe-auto", FALSE,
+          "keyframe-force", 25, NULL);
+      name = "Theora video encoder";
+      break;
+
+    case VIDEO_ENCODER_VP8:
+    default:
+      gve->priv->video_enc =
+          gst_element_factory_make ("vp8enc", "video-encoder");
+      g_object_set (gve->priv->video_enc, "speed", 2, "threads", 8,
+          "max-keyframe-distance", 25, NULL);
+      name = "VP8 video encoder";
+      break;
+
+  }
+  if (!gve->priv->video_enc) {
+    g_set_error (err,
+        GVE_ERROR,
+        GST_ERROR_PLUGIN_LOAD,
+        "Failed to create the %s element. "
+        "Please check your GStreamer installation.", name);
+    return FALSE;
+  }
+
+  if (gve->priv->video_encoder_type == VIDEO_ENCODER_MPEG4 ||
+      gve->priv->video_encoder_type == VIDEO_ENCODER_XVID)
+    g_object_set (gve->priv->video_enc, "bitrate", gve->priv->video_bitrate * 1000, NULL);
+  else
+    g_object_set (gve->priv->video_enc, "bitrate", gve->priv->video_bitrate,
+        NULL);
+
+  GST_INFO_OBJECT(gve, "Video encoder %s created", name);
+  gve->priv->video_encoder_type = type;
+  return TRUE;
+}
+
+static gboolean
+gst_video_encoder_create_audio_encoder (GstVideoEncoder * gve,
+    AudioEncoderType type, GError ** err)
+{
+  gchar *name = NULL;
+
+  g_return_val_if_fail (gve != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_VIDEO_ENCODER (gve), FALSE);
+
+  switch (type) {
+    case AUDIO_ENCODER_MP3:
+      gve->priv->audio_enc =
+          gst_element_factory_make ("lamemp3enc", "audio-encoder");
+      g_object_set (gve->priv->audio_enc, "target", 0, NULL);
+      name = "Mp3 audio encoder";
+      break;
+
+    case AUDIO_ENCODER_AAC:
+      gve->priv->audio_enc = gst_element_factory_make ("faac", "audio-encoder");
+      name = "AAC audio encoder";
+      break;
+
+    case AUDIO_ENCODER_VORBIS:
+    default:
+      gve->priv->audio_enc =
+          gst_element_factory_make ("vorbisenc", "audio-encoder");
+      name = "Vorbis audio encoder";
+      break;
+  }
+
+  if (!gve->priv->audio_enc) {
+    g_set_error (err,
+        GVE_ERROR,
+        GST_ERROR_PLUGIN_LOAD,
+        "Failed to create the %s element. "
+        "Please check your GStreamer installation.", name);
+    return FALSE;
+  }
+
+  if (gve->priv->audio_encoder_type == AUDIO_ENCODER_MP3)
+    g_object_set (gve->priv->audio_enc, "bitrate", gve->priv->audio_bitrate, NULL);
+  else
+    g_object_set (gve->priv->audio_enc, "bitrate", 1000 * gve->priv->audio_bitrate, NULL);
+
+  GST_INFO_OBJECT(gve, "Audio encoder %s created", name);
+
+  gve->priv->audio_encoder_type = type;
+  return TRUE;
+}
+
+static gboolean
+gst_video_encoder_create_video_muxer (GstVideoEncoder * gve,
+    VideoMuxerType type, GError ** err)
+{
+  gchar *name = NULL;
+
+  g_return_val_if_fail (gve != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_VIDEO_ENCODER (gve), FALSE);
+
+  switch (type) {
+    case VIDEO_MUXER_OGG:
+      name = "OGG muxer";
+      gve->priv->muxer = gst_element_factory_make ("oggmux", "video-muxer");
+      break;
+    case VIDEO_MUXER_AVI:
+      name = "AVI muxer";
+      gve->priv->muxer = gst_element_factory_make ("avimux", "video-muxer");
+      break;
+    case VIDEO_MUXER_MATROSKA:
+      name = "Matroska muxer";
+      gve->priv->muxer =
+          gst_element_factory_make ("matroskamux", "video-muxer");
+      break;
+    case VIDEO_MUXER_MP4:
+      name = "MP4 muxer";
+      gve->priv->muxer = gst_element_factory_make ("qtmux", "video-muxer");
+      break;
+    case VIDEO_MUXER_WEBM:
+    default:
+      name = "WebM muxer";
+      gve->priv->muxer = gst_element_factory_make ("webmmux", "video-muxer");
+      break;
+  }
+
+  if (!gve->priv->muxer) {
+    g_set_error (err,
+        GVE_ERROR,
+        GST_ERROR_PLUGIN_LOAD,
+        "Failed to create the %s element. "
+        "Please check your GStreamer installation.", name);
+  }
+
+  GST_INFO_OBJECT(gve, "Muxer %s created", name);
+  gve->priv->video_muxer_type = type;
+  return TRUE;
+}
+
+static void
+gst_video_encoder_initialize (GstVideoEncoder *gve)
+{
+  GError *err= NULL;
+
+  GST_INFO_OBJECT (gve, "Initializing encoders");
+  if (!gst_video_encoder_create_video_encoder(gve,
+        gve->priv->video_encoder_type, &err))
+    goto missing_plugin;
+  if (!gst_video_encoder_create_audio_encoder(gve,
+        gve->priv->audio_encoder_type, &err))
+    goto missing_plugin;
+  if (!gst_video_encoder_create_video_muxer(gve,
+        gve->priv->video_muxer_type, &err))
+    goto missing_plugin;
+
+  gst_video_encoder_create_encoder_bin (gve);
+  gst_video_encoder_select_next_file (gve);
+  gst_element_set_state (gve->priv->main_pipeline, GST_STATE_PLAYING);
+  return;
+
+missing_plugin:
+    g_signal_emit (gve, gve_signals[SIGNAL_ERROR], 0, err->message);
+    g_error_free (err);
+}
+
+static void
+gve_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
+{
+  GstVideoEncoder *gve = (GstVideoEncoder *) data;
+  GstMessageType msg_type;
+
+  g_return_if_fail (gve != NULL);
+  g_return_if_fail (GST_IS_VIDEO_ENCODER (gve));
+
+  msg_type = GST_MESSAGE_TYPE (message);
+
+  switch (msg_type) {
+    case GST_MESSAGE_ERROR:
+    {
+      if (gve->priv->main_pipeline) {
+        gst_video_encoder_cancel (gve);
+        gst_element_set_state (gve->priv->main_pipeline, GST_STATE_NULL);
+      }
+      gve_error_msg (gve, message);
+      break;
+    }
+
+    case GST_MESSAGE_WARNING:
+    {
+      GST_WARNING ("Warning message: %" GST_PTR_FORMAT, message);
+      break;
+    }
+
+    case GST_MESSAGE_EOS:
+    {
+      GST_INFO_OBJECT (gve, "EOS message");
+      g_signal_emit (gve, gve_signals[SIGNAL_PERCENT_COMPLETED], 0, (gfloat) 1);
+      break;
+    }
+
+    default:
+      GST_LOG ("Unhandled message: %" GST_PTR_FORMAT, message);
+      break;
+  }
+}
+
+static void
+gve_error_msg (GstVideoEncoder * gve, GstMessage * msg)
+{
+  GError *err = NULL;
+  gchar *dbg = NULL;
+
+  gst_message_parse_error (msg, &err, &dbg);
+  if (err) {
+    GST_ERROR ("message = %s", GST_STR_NULL (err->message));
+    GST_ERROR ("domain  = %d (%s)", err->domain,
+        GST_STR_NULL (g_quark_to_string (err->domain)));
+    GST_ERROR ("code    = %d", err->code);
+    GST_ERROR ("debug   = %s", GST_STR_NULL (dbg));
+    GST_ERROR ("source  = %" GST_PTR_FORMAT, msg->src);
+
+
+    g_message ("Error: %s\n%s\n", GST_STR_NULL (err->message),
+        GST_STR_NULL (dbg));
+    g_signal_emit (gve, gve_signals[SIGNAL_ERROR], 0, err->message);
+    g_error_free (err);
+  }
+  g_free (dbg);
+}
+
+
+/*******************************************
+ *
+ *         Public methods
+ *
+ * ****************************************/
+
+void
+gst_video_encoder_cancel (GstVideoEncoder * gve)
+{
+  g_return_if_fail (gve != NULL);
+  g_return_if_fail (GST_IS_VIDEO_ENCODER (gve));
+
+  gst_element_set_state (gve->priv->main_pipeline, GST_STATE_NULL);
+  gst_element_get_state (gve->priv->main_pipeline, NULL, NULL, -1);
+}
+
+void
+gst_video_encoder_start (GstVideoEncoder * gve)
+{
+  g_return_if_fail (gve != NULL);
+  g_return_if_fail (GST_IS_VIDEO_ENCODER (gve));
+
+  GST_INFO_OBJECT(gve, "Starting encoding");
+  gst_video_encoder_initialize (gve);
+}
+
+void
+gst_video_encoder_add_file (GstVideoEncoder * gve, const gchar *file)
+{
+  g_return_if_fail (gve != NULL);
+  g_return_if_fail (GST_IS_VIDEO_ENCODER (gve));
+
+  GST_INFO_OBJECT(gve, "Adding file %s", file);
+  gve->priv->input_files = g_list_append (gve->priv->input_files, g_strdup(file));
+}
+
+gboolean
+gst_video_encoder_dump_graph (GstVideoEncoder * gve)
+{
+  GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (gve->priv->main_pipeline),
+      GST_DEBUG_GRAPH_SHOW_ALL, "gst-video-encoder.dot");
+  return FALSE;
+}
+
+void
+gst_video_encoder_set_encoding_format (GstVideoEncoder * gve,
+    VideoEncoderType video_codec, AudioEncoderType audio_codec,
+    VideoMuxerType muxer, guint video_bitrate, guint audio_bitrate,
+    guint width, guint height, guint fps_n, guint fps_d)
+{
+  gve->priv->video_encoder_type = video_codec;
+  gve->priv->audio_encoder_type = audio_codec;
+  gve->priv->video_muxer_type = muxer;
+  gve->priv->video_bitrate = video_bitrate;
+  gve->priv->audio_bitrate = audio_bitrate;
+  gve->priv->output_width = width;
+  gve->priv->output_height = height;
+  gve->priv->fps_n = fps_n;
+  gve->priv->fps_d = fps_d;
+
+}
+GstVideoEncoder *
+gst_video_encoder_new (gchar * filename, GError ** err)
+{
+  GstVideoEncoder *gve = NULL;
+
+#ifndef GST_DISABLE_GST_INFO
+  if (_video_encoder_gst_debug_cat == NULL) {
+    GST_DEBUG_CATEGORY_INIT (_video_encoder_gst_debug_cat, "longomatch", 0,
+        "LongoMatch GStreamer Backend");
+  }
+#endif
+
+  gve = g_object_new (GST_TYPE_VIDEO_ENCODER, NULL);
+
+  gve->priv->output_file = g_strdup (filename);
+  gve->priv->main_pipeline = gst_pipeline_new ("main_pipeline");
+
+  if (!gve->priv->main_pipeline) {
+    g_set_error (err,
+        GVE_ERROR,
+        GST_ERROR_PLUGIN_LOAD,
+        "Failed to create the pipeline element. "
+        "Please check your GStreamer installation.");
+    goto missing_plugin;
+  }
+
+  /*Connect bus signals */
+  GST_INFO_OBJECT (gve, "Connecting bus signals");
+  gve->priv->bus = gst_element_get_bus (GST_ELEMENT (gve->priv->main_pipeline));
+  gst_bus_add_signal_watch (gve->priv->bus);
+  gve->priv->sig_bus_async =
+      g_signal_connect (gve->priv->bus, "message",
+      G_CALLBACK (gve_bus_message_cb), gve);
+
+  return gve;
+
+/* Missing plugin */
+missing_plugin:
+  {
+    g_object_ref_sink (gve);
+    g_object_unref (gve);
+    return NULL;
+  }
+}
diff --git a/libcesarplayer/gst-video-encoder.h b/libcesarplayer/gst-video-encoder.h
new file mode 100644
index 0000000..61bd146
--- /dev/null
+++ b/libcesarplayer/gst-video-encoder.h
@@ -0,0 +1,92 @@
+/*
+ * Gstreamer Multi File Source Bin
+ * Copyright (C) 2013 Andoni Morales Alastruey <ylatuya gmail com>
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * foob is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with foob.  If not, write to:
+ *      The Free Software Foundation, Inc.,
+ *      51 Franklin Street, Fifth Floor
+ *      Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _GST_VIDEO_ENCODER_H_
+#define _GST_VIDEO_ENCODER_H_
+
+#ifdef WIN32
+#define EXPORT __declspec (dllexport)
+#else
+#define EXPORT
+#endif
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "common.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_VIDEO_ENCODER             (gst_video_encoder_get_type ())
+#define GST_VIDEO_ENCODER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VIDEO_ENCODER, 
GstVideoEncoder))
+#define GST_VIDEO_ENCODER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VIDEO_ENCODER, 
GstVideoEncoderClass))
+#define GST_IS_VIDEO_ENCODER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VIDEO_ENCODER))
+#define GST_IS_VIDEO_ENCODER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VIDEO_ENCODER))
+#define GST_VIDEO_ENCODER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VIDEO_ENCODER, 
GstVideoEncoderClass))
+#define GVE_ERROR gst_video_encoder_error_quark ()
+
+typedef struct _GstVideoEncoderClass GstVideoEncoderClass;
+typedef struct _GstVideoEncoder GstVideoEncoder;
+typedef struct GstVideoEncoderPrivate GstVideoEncoderPrivate;
+
+
+struct _GstVideoEncoderClass
+{
+  GObjectClass parent_class;
+
+  void (*error) (GstVideoEncoder * gve, const char *message);
+  void (*percent_completed) (GstVideoEncoder * gve, float percent);
+};
+
+struct _GstVideoEncoder
+{
+  GObject parent_instance;
+  GstVideoEncoderPrivate *priv;
+};
+
+EXPORT GType gst_video_encoder_get_type (void) G_GNUC_CONST;
+
+EXPORT void gst_video_encoder_init_backend                     (int *argc, char ***argv);
+
+EXPORT GstVideoEncoder *gst_video_encoder_new                  (gchar *output_file, GError ** err);
+
+EXPORT void gst_video_encoder_start                            (GstVideoEncoder * gve);
+
+EXPORT void gst_video_encoder_cancel                           (GstVideoEncoder * gve);
+
+EXPORT void gst_video_encoder_set_encoding_format              (GstVideoEncoder * gve,
+                                                                VideoEncoderType video_codec,
+                                                                AudioEncoderType audio_codec,
+                                                                VideoMuxerType muxer,
+                                                                guint video_bitrate,
+                                                                guint audio_bitrate,
+                                                                guint height,
+                                                                guint width,
+                                                                guint fps_n,
+                                                                guint fps_d);
+
+EXPORT void gst_video_encoder_add_file                         (GstVideoEncoder * gve,
+                                                                const gchar * file);
+
+EXPORT gboolean gst_video_encoder_dump_graph                   (GstVideoEncoder *gve);
+
+G_END_DECLS
+#endif /* _GST_VIDEO_ENCODER_H_ */
diff --git a/libcesarplayer/test-encoder.c b/libcesarplayer/test-encoder.c
new file mode 100644
index 0000000..6913d42
--- /dev/null
+++ b/libcesarplayer/test-encoder.c
@@ -0,0 +1,93 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * main.c
+ * Copyright (C) Andoni Morales Alastruey 2008 <ylatuya gmail com>
+ * 
+ * main.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * main.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "gst-video-encoder.h"
+
+static GMainLoop *loop;
+
+static gboolean
+percent_done_cb (GstVideoEncoder *remuxer, gfloat percent, GstVideoEncoder *editor)
+{
+  if (percent == 1) {
+    g_print("SUCESS!\n");
+    g_main_loop_quit (loop);
+  } else {
+    g_print("----> %f%%\n", percent);
+  }
+  return TRUE;
+}
+
+static gboolean
+error_cb (GstVideoEncoder *remuxer, gchar *error, GstVideoEncoder *editor)
+{
+    g_print("ERROR: %s\n", error);
+    g_main_loop_quit (loop);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstVideoEncoder *encoder;
+  VideoEncoderType video_encoder;
+  VideoMuxerType video_muxer;
+  AudioEncoderType audio_encoder;
+  gchar *input_file, *output_file;
+  GError *err = NULL;
+  guint64 start, stop;
+  gint i;
+
+  gst_video_encoder_init_backend (&argc, &argv);
+
+  if (argc < 3) {
+    g_print("Usage: test-remuxer output_file input_files \n");
+    return 1;
+  }
+
+  output_file = argv[1];
+  input_file = argv[1];
+
+  video_encoder = VIDEO_ENCODER_H264;
+  video_muxer = VIDEO_MUXER_MP4;
+  audio_encoder = AUDIO_ENCODER_AAC;
+
+  encoder = gst_video_encoder_new (output_file, &err);
+  gst_video_encoder_set_encoding_format (encoder, video_encoder,
+      audio_encoder, video_muxer, 5000, 128, 720, 480, 25, 1);
+
+  for (i=2; i < argc; i++) {
+    gst_video_encoder_add_file (encoder, argv[i]);
+  }
+
+  loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (encoder, "error", G_CALLBACK (error_cb), encoder);
+  g_signal_connect (encoder, "percent_completed", G_CALLBACK(percent_done_cb),
+      encoder);
+  gst_video_encoder_start (encoder);
+  g_main_loop_run (loop);
+
+  return 0;
+
+error:
+  g_print ("ERROR: %s", err->message);
+  return 1;
+
+}
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]