[longomatch/camera_capturer] rewrite the camera capturer to support more sources
- From: Andoni Morales Alastruey <amorales src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [longomatch/camera_capturer] rewrite the camera capturer to support more sources
- Date: Wed, 3 Oct 2012 01:08:00 +0000 (UTC)
commit 99e6b53e2cd0d946840862a5a52693bfe4eb1207
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date: Mon Oct 1 02:20:29 2012 +0200
rewrite the camera capturer to support more sources
LongoMatch.Core/Common/CaptureSettings.cs | 2 +-
LongoMatch.Core/Common/Device.cs | 14 +-
LongoMatch.Core/Common/Enums.cs | 9 +-
.../Gui/Component/ProjectDetailsWidget.cs | 17 +-
.../gtk-gui/LongoMatch.Gui.MainWindow.cs | 4 +-
LongoMatch.GUI/gtk-gui/objects.xml | 34 +-
.../Capturer/GstCameraCapturer.cs | 30 -
LongoMatch.Multimedia/Utils/VideoDevice.cs | 40 +-
LongoMatch.Services/Services/ProjectsManager.cs | 3 +-
configure.ac | 2 +-
libcesarplayer/bacon-video-widget-gst-0.10.c | 20 -
libcesarplayer/common.h | 38 +
libcesarplayer/gst-camera-capturer.c | 1564 +++++++++++++-------
libcesarplayer/gst-camera-capturer.h | 47 +-
libcesarplayer/gstscreenshot.c | 3 +-
libcesarplayer/liblongomatch.mdp | 3 +-
libcesarplayer/main.c | 37 +-
libcesarplayer/video-utils.c | 35 +-
libcesarplayer/video-utils.h | 33 +-
19 files changed, 1251 insertions(+), 684 deletions(-)
---
diff --git a/LongoMatch.Core/Common/CaptureSettings.cs b/LongoMatch.Core/Common/CaptureSettings.cs
index 1932c1f..4f5a7fd 100644
--- a/LongoMatch.Core/Common/CaptureSettings.cs
+++ b/LongoMatch.Core/Common/CaptureSettings.cs
@@ -29,7 +29,7 @@ namespace LongoMatch.Common
public static CaptureSettings DefaultSettings() {
CaptureSettings settings = new CaptureSettings();
- settings.CaptureSourceType = CaptureSourceType.Raw;
+ settings.CaptureSourceType = CaptureSourceType.System;
settings.EncodingSettings = new EncodingSettings(VideoStandards.P480_4_3,
EncodingProfiles.MP4,
25, 1, 1000, 128, "", 20);
diff --git a/LongoMatch.Core/Common/Device.cs b/LongoMatch.Core/Common/Device.cs
index e27c303..e227865 100644
--- a/LongoMatch.Core/Common/Device.cs
+++ b/LongoMatch.Core/Common/Device.cs
@@ -32,9 +32,9 @@ namespace LongoMatch.Common
}
/// <summary>
- /// Device Type among Video, Audio or DV (for dv cameras)
+ /// Capture source type
/// </summary>
- public DeviceType DeviceType {
+ public CaptureSourceType DeviceType {
get;
set;
}
@@ -47,15 +47,5 @@ namespace LongoMatch.Common
get;
set;
}
-
- /// <summary>
- /// The name of the gstreamer element property used to set the device
- /// </summary>
-
- public string IDProperty {
- get;
- set;
- }
-
}
}
diff --git a/LongoMatch.Core/Common/Enums.cs b/LongoMatch.Core/Common/Enums.cs
index f0bb2b4..2ca7ca6 100644
--- a/LongoMatch.Core/Common/Enums.cs
+++ b/LongoMatch.Core/Common/Enums.cs
@@ -108,14 +108,7 @@ namespace LongoMatch.Common
public enum CaptureSourceType {
None,
DV,
- Raw,
- DShow
- }
-
- public enum DeviceType {
- Video,
- Audio,
- DV
+ System,
}
public enum GameUnitEventType {
diff --git a/LongoMatch.GUI/Gui/Component/ProjectDetailsWidget.cs b/LongoMatch.GUI/Gui/Component/ProjectDetailsWidget.cs
index aae413d..6932b61 100644
--- a/LongoMatch.GUI/Gui/Component/ProjectDetailsWidget.cs
+++ b/LongoMatch.GUI/Gui/Component/ProjectDetailsWidget.cs
@@ -235,15 +235,7 @@ namespace LongoMatch.Gui.Component
encSettings.OutputFile = fileEntry.Text;
encSettings.AudioBitrate = (uint)audiobitratespinbutton.Value;
encSettings.VideoBitrate = (uint)videobitratespinbutton.Value;
- if(videoDevices[devicecombobox.Active].DeviceType == DeviceType.DV) {
- if(Environment.OSVersion.Platform == PlatformID.Win32NT)
- s.CaptureSourceType = CaptureSourceType.DShow;
- else
- s.CaptureSourceType = CaptureSourceType.DV;
- }
- else {
- s.CaptureSourceType = CaptureSourceType.Raw;
- }
+ s.CaptureSourceType = videoDevices[devicecombobox.Active].DeviceType;
s.DeviceID = videoDevices[devicecombobox.Active].ID;
/* Get size info */
@@ -354,12 +346,15 @@ namespace LongoMatch.Gui.Component
string deviceElement;
string deviceName;
if(Environment.OSVersion.Platform == PlatformID.Unix) {
- if(device.DeviceType == DeviceType.DV)
+ if(device.DeviceType == CaptureSourceType.DV)
deviceElement = Catalog.GetString(DV_SOURCE);
else
deviceElement = Catalog.GetString(GCONF_SOURCE);
- } else
+ } else if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
deviceElement = Catalog.GetString("DirectShow Source");
+ } else {
+ deviceElement = Catalog.GetString("OS X Source");
+ }
deviceName = (device.ID == "") ? Catalog.GetString("Unknown"): device.ID;
devicecombobox.AppendText(deviceName + " ("+deviceElement+")");
devicecombobox.Active = 0;
diff --git a/LongoMatch.GUI/gtk-gui/LongoMatch.Gui.MainWindow.cs b/LongoMatch.GUI/gtk-gui/LongoMatch.Gui.MainWindow.cs
index 781fd51..72d0dc4 100644
--- a/LongoMatch.GUI/gtk-gui/LongoMatch.Gui.MainWindow.cs
+++ b/LongoMatch.GUI/gtk-gui/LongoMatch.Gui.MainWindow.cs
@@ -135,12 +135,12 @@ namespace LongoMatch.Gui
this.ImportProjectAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("_Import Project");
w1.Add (this.ImportProjectAction, "<Control>i");
this.ManualTaggingViewAction = new global::Gtk.RadioAction ("ManualTaggingViewAction", global::Mono.Unix.Catalog.GetString ("Manual tagging view"), null, null, 0);
- this.ManualTaggingViewAction.Group = this.TaggingViewAction.Group;
+ this.ManualTaggingViewAction.Group = this.TimelineViewAction.Group;
this.ManualTaggingViewAction.Sensitive = false;
this.ManualTaggingViewAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Free Capture Mode");
w1.Add (this.ManualTaggingViewAction, "<Control>f");
this.GameUnitsViewAction = new global::Gtk.RadioAction ("GameUnitsViewAction", global::Mono.Unix.Catalog.GetString ("Game units view"), null, null, 0);
- this.GameUnitsViewAction.Group = this.TaggingViewAction.Group;
+ this.GameUnitsViewAction.Group = this.TimelineViewAction.Group;
this.GameUnitsViewAction.Sensitive = false;
this.GameUnitsViewAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Game units view");
w1.Add (this.GameUnitsViewAction, null);
diff --git a/LongoMatch.GUI/gtk-gui/objects.xml b/LongoMatch.GUI/gtk-gui/objects.xml
index f943be7..0d24ee1 100644
--- a/LongoMatch.GUI/gtk-gui/objects.xml
+++ b/LongoMatch.GUI/gtk-gui/objects.xml
@@ -244,23 +244,6 @@
</itemgroup>
</signals>
</object>
- <object type="LongoMatch.Gui.Component.ProjectDetailsWidget" palette-category="LongoMatch" allow-children="false" base-type="Gtk.Bin">
- <itemgroups>
- <itemgroup label="ProjectDetailsWidget Properties">
- <property name="Edited" />
- <property name="Season" />
- <property name="Competition" />
- <property name="LocalGoals" />
- <property name="VisitorGoals" />
- <property name="Date" />
- </itemgroup>
- </itemgroups>
- <signals>
- <itemgroup label="ProjectDetailsWidget Signals">
- <signal name="EditedEvent" />
- </itemgroup>
- </signals>
- </object>
<object type="LongoMatch.Gui.Component.PlayersFilterTreeView" palette-category="LongoMatch" allow-children="false" base-type="Gtk.TreeView">
<itemgroups />
<signals />
@@ -278,4 +261,21 @@
</itemgroup>
</signals>
</object>
+ <object type="LongoMatch.Gui.Component.ProjectDetailsWidget" palette-category="LongoMatch" allow-children="false" base-type="Gtk.Bin">
+ <itemgroups>
+ <itemgroup label="ProjectDetailsWidget Properties">
+ <property name="Edited" />
+ <property name="Season" />
+ <property name="Competition" />
+ <property name="LocalGoals" />
+ <property name="VisitorGoals" />
+ <property name="Date" />
+ </itemgroup>
+ </itemgroups>
+ <signals>
+ <itemgroup label="ProjectDetailsWidget Signals">
+ <signal name="EditedEvent" />
+ </itemgroup>
+ </signals>
+ </object>
</objects>
\ No newline at end of file
diff --git a/LongoMatch.Multimedia/Capturer/GstCameraCapturer.cs b/LongoMatch.Multimedia/Capturer/GstCameraCapturer.cs
index 2e29521..d41dfe5 100644
--- a/LongoMatch.Multimedia/Capturer/GstCameraCapturer.cs
+++ b/LongoMatch.Multimedia/Capturer/GstCameraCapturer.cs
@@ -491,35 +491,5 @@ namespace LongoMatch.Video.Capturer {
}
#endregion
- static public List<Device> ListVideoDevices() {
- List<Device> devicesList = new List<Device>();
-
- /* Generate the list of devices and add the gconf one at the bottom
- * so that DV sources are always selected before, at least on Linux,
- * since on Windows both raw an dv sources are listed from the same
- * source element (dshowvideosrc) */
- foreach(string devName in GstCameraCapturer.VideoDevices) {
- string idProp;
-
- if(Environment.OSVersion.Platform == PlatformID.Unix)
- idProp = VideoConstants.DV1394SRC_PROP;
- else
- idProp = VideoConstants.DSHOWVIDEOSINK_PROP;
-
- devicesList.Add(new Device {
- ID = devName,
- IDProperty = idProp,
- DeviceType = DeviceType.DV
- });
- }
- if(Environment.OSVersion.Platform == PlatformID.Unix) {
- devicesList.Add(new Device {
- ID = Catalog.GetString("Default device"),
- IDProperty = "",
- DeviceType = DeviceType.Video
- });
- }
- return devicesList;
- }
}
}
diff --git a/LongoMatch.Multimedia/Utils/VideoDevice.cs b/LongoMatch.Multimedia/Utils/VideoDevice.cs
index e6ada1c..5a208f8 100644
--- a/LongoMatch.Multimedia/Utils/VideoDevice.cs
+++ b/LongoMatch.Multimedia/Utils/VideoDevice.cs
@@ -28,35 +28,33 @@ namespace LongoMatch.Multimedia.Utils
public class VideoDevice
{
- static public List<Device> ListVideoDevices (){
+ static public List<Device> ListVideoDevices() {
List<Device> devicesList = new List<Device>();
-
- /* Generate the list of devices and add the gconf one at the bottom
- * so that DV sources are always selected before, at least on Linux,
- * since on Windows both raw an dv sources are listed from the same
- * source element (dshowvideosrc) */
- foreach (string devName in GstCameraCapturer.VideoDevices){
- string idProp;
-
- if (Environment.OSVersion.Platform == PlatformID.Unix)
- idProp = VideoConstants.DV1394SRC_PROP;
- else
- idProp = VideoConstants.DSHOWVIDEOSINK_PROP;
-
+
+ /* Generate the list of devices, on the supported platforms
+ * and extra DV device for the dv1394src element and the default
+ * OS source for all of them */
+ foreach(string devName in GstCameraCapturer.VideoDevices) {
+ CaptureSourceType source;
+
+ if(Environment.OSVersion.Platform == PlatformID.Unix)
+ source = CaptureSourceType.DV;
+ else
+ source = CaptureSourceType.System;
+
devicesList.Add(new Device {
ID = devName,
- IDProperty = idProp,
- DeviceType = DeviceType.DV});
+ DeviceType = source,
+ });
}
- if (Environment.OSVersion.Platform == PlatformID.Unix){
+ if(Environment.OSVersion.Platform != PlatformID.Win32NT) {
devicesList.Add(new Device {
ID = Catalog.GetString("Default device"),
- IDProperty = "",
- DeviceType = DeviceType.Video});
- }
+ DeviceType = CaptureSourceType.System
+ });
+ }
return devicesList;
}
-
}
}
diff --git a/LongoMatch.Services/Services/ProjectsManager.cs b/LongoMatch.Services/Services/ProjectsManager.cs
index f7e1c43..2abf520 100644
--- a/LongoMatch.Services/Services/ProjectsManager.cs
+++ b/LongoMatch.Services/Services/ProjectsManager.cs
@@ -111,8 +111,7 @@ namespace LongoMatch.Services
filePath+"\n"+projectFile);
}
/* we need to set the opened project to null to avoid calling again CloseOpendProject() */
- /* FIXME: */
- //project = null;
+ OpenedProject = null;
SetProject(project, ProjectType.FileProject, new CaptureSettings());
}
diff --git a/configure.ac b/configure.ac
index 45c559d..830926a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,7 +81,7 @@ PKG_CHECK_MODULES([MONO_ADDINS], [mono-addins])
AC_SUBST(MONO_ADDINS_LIBS)
dnl package checks for libcesarplayer
-PKG_CHECK_MODULES(CESARPLAYER, [gtk+-2.0 >= 2.8 gdk-2.0 gio-2.0 glib-2.0 gstreamer-0.10 gstreamer-audio-0.10 gstreamer-video-0.10 gstreamer-pbutils-0.10 gobject-2.0 gstreamer-interfaces-0.10 gstreamer-tag-0.10])
+PKG_CHECK_MODULES(CESARPLAYER, [gtk+-2.0 >= 2.8 gdk-2.0 gio-2.0 glib-2.0 gstreamer-0.10 gstreamer-audio-0.10 gstreamer-video-0.10 gstreamer-pbutils-0.10 gobject-2.0 gstreamer-interfaces-0.10 gstreamer-tag-0.10 gstreamer-app-0.10])
AC_SUBST(CESARPLAYER_CFLAGS)
AC_SUBST(CESARPLAYER_LIBS)
diff --git a/libcesarplayer/bacon-video-widget-gst-0.10.c b/libcesarplayer/bacon-video-widget-gst-0.10.c
index be259d9..2f0aa6f 100644
--- a/libcesarplayer/bacon-video-widget-gst-0.10.c
+++ b/libcesarplayer/bacon-video-widget-gst-0.10.c
@@ -67,16 +67,6 @@
#include <gtk/gtk.h>
-#if defined(OSTYPE_WINDOWS)
-#define DEFAULT_VIDEO_SINK "autovideosink"
-#define BACKUP_VIDEO_SINK "autovideosink"
-#elif defined(OSTYPE_OS_X)
-#define DEFAULT_VIDEO_SINK "autovideosink"
-#define BACKUP_VIDEO_SINK "autovideosink"
-#elif defined(OSTYPE_LINUX)
-#define DEFAULT_VIDEO_SINK "gsettingsvideosink"
-#define BACKUP_VIDEO_SINK "autovideosink"
-#endif
#include <gio/gio.h>
#include <glib/gi18n.h>
@@ -259,9 +249,6 @@ static GThread *gui_thread;
static int bvw_signals[LAST_SIGNAL] = { 0 };
-GST_DEBUG_CATEGORY (_totem_gst_debug_cat);
-#define GST_CAT_DEFAULT _totem_gst_debug_cat
-
typedef gchar *(*MsgToStrFunc) (GstMessage * msg);
@@ -5405,13 +5392,6 @@ bacon_video_widget_new (int width, int height, BvwUseType type, GError ** err)
GstElement *audio_sink = NULL, *video_sink = NULL;
gchar *version_str;
-#ifndef GST_DISABLE_GST_INFO
- if (_totem_gst_debug_cat == NULL) {
- GST_DEBUG_CATEGORY_INIT (_totem_gst_debug_cat, "totem", 0,
- "Totem GStreamer Backend");
- }
-#endif
-
version_str = gst_version_string ();
GST_INFO ("Initialised %s", version_str);
g_free (version_str);
diff --git a/libcesarplayer/common.h b/libcesarplayer/common.h
index cb3ed97..4c9ada2 100644
--- a/libcesarplayer/common.h
+++ b/libcesarplayer/common.h
@@ -17,6 +17,35 @@
*
*/
+#ifndef __LIBCESARPLAYER_COMMON_H__
+#define __LIBCESARPLAYER_COMMON_H__
+
+/* Default video/audio sinks */
+#if defined(OSTYPE_WINDOWS)
+#define DEFAULT_VIDEO_SINK "autovideosink"
+#define BACKUP_VIDEO_SINK "autovideosink"
+#elif defined(OSTYPE_OS_X)
+#define DEFAULT_VIDEO_SINK "autovideosink"
+#define BACKUP_VIDEO_SINK "autovideosink"
+#elif defined(OSTYPE_LINUX)
+#define DEFAULT_VIDEO_SINK "gsettingsvideosink"
+#define BACKUP_VIDEO_SINK "autovideosink"
+#endif
+
+/*Default video/audio source*/
+#if defined(OSTYPE_WINDOWS)
+#define DVVIDEOSRC "dshowvideosrc"
+#define SYSVIDEOSRC "dshowvideosrc"
+#define AUDIOSRC "dshowaudiosrc"
+#elif defined(OSTYPE_OS_X)
+#define DVVIDEOSRC "dv1394src"
+#define SYSVIDEOSRC "osxvideosrc"
+#define AUDIOSRC "osxaudiosrc"
+#elif defined(OSTYPE_LINUX)
+#define DVVIDEOSRC "dv1394src"
+#define SYSVIDEOSRC "gsettingsvideosrc"
+#define AUDIOSRC "gsettingsaudiosrc"
+#endif
/**
* Error:
@@ -104,3 +133,12 @@ typedef enum
VIDEO_MUXER_MPEG_PS,
VIDEO_MUXER_WEBM
} VideoMuxerType;
+
+typedef enum
+{
+ CAPTURE_SOURCE_TYPE_NONE = 0,
+ CAPTURE_SOURCE_TYPE_DV = 1,
+ CAPTURE_SOURCE_TYPE_SYSTEM = 2,
+} CaptureSourceType;
+
+#endif
diff --git a/libcesarplayer/gst-camera-capturer.c b/libcesarplayer/gst-camera-capturer.c
index 58f7f9b..e0f7c65 100644
--- a/libcesarplayer/gst-camera-capturer.c
+++ b/libcesarplayer/gst-camera-capturer.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <stdio.h>
+#include <gst/app/gstappsrc.h>
#include <gst/interfaces/xoverlay.h>
#include <gst/interfaces/propertyprobe.h>
#include <gst/gst.h>
@@ -32,23 +33,9 @@
#include "gst-camera-capturer.h"
#include "gstscreenshot.h"
+#include "common.h"
+#include "video-utils.h"
-/*Default video source*/
-#if defined(OSTYPE_WINDOWS)
-#define DVVIDEOSRC "dshowvideosrc"
-#define RAWVIDEOSRC "dshowvideosrc"
-#define AUDIOSRC "dshowaudiosrc"
-#elif defined(OSTYPE_OS_X)
-#define DVVIDEOSRC "osxvideosrc"
-#define RAWVIDEOSRC "osxvideosrc"
-#define AUDIOSRC "osxaudiosrc"
-#elif defined(OSTYPE_LINUX)
-#define DVVIDEOSRC "dv1394src"
-#define RAWVIDEOSRC "gsettingsvideosrc"
-#define AUDIOSRC "gsettingsaudiosrc"
-#define RAWVIDEOSRC_GCONF "gconfvideosrc"
-#define AUDIOSRC_GCONF "gconfaudiosrc"
-#endif
/* gtk+/gnome */
#include <gdk/gdk.h>
@@ -61,22 +48,8 @@
#endif
#include <gtk/gtk.h>
-#ifdef WIN32
-#define DEFAULT_SOURCE_TYPE GST_CAMERA_CAPTURE_SOURCE_TYPE_DSHOW
-#else
-#define DEFAULT_SOURCE_TYPE GST_CAMERA_CAPTURE_SOURCE_TYPE_RAW
-#endif
-
-typedef enum
-{
- GST_CAMERABIN_FLAG_SOURCE_RESIZE = (1 << 0),
- GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION = (1 << 1),
- GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION = (1 << 2),
- GST_CAMERABIN_FLAG_VIEWFINDER_SCALE = (1 << 3),
- GST_CAMERABIN_FLAG_AUDIO_CONVERSION = (1 << 4),
- GST_CAMERABIN_FLAG_DISABLE_AUDIO = (1 << 5),
- GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION = (1 << 6)
-} GstCameraBinFlags;
+GST_DEBUG_CATEGORY (_cesarplayer_gst_debug_cat);
+#define GST_CAT_DEFAULT _cesarplayer_gst_debug_cat
/* Signals */
enum
@@ -109,13 +82,13 @@ struct GstCameraCapturerPrivate
gchar *device_id;
guint output_height;
guint output_width;
- guint output_fps_n;
- guint output_fps_d;
guint audio_bitrate;
guint video_bitrate;
gboolean audio_enabled;
VideoEncoderType video_encoder_type;
AudioEncoderType audio_encoder_type;
+ VideoMuxerType video_muxer_type;
+ CaptureSourceType source_type;
/*Video input info */
gint video_width; /* Movie width */
@@ -127,21 +100,38 @@ struct GstCameraCapturerPrivate
gint video_fps_d;
gboolean media_has_video;
gboolean media_has_audio;
- GstCameraCaptureSourceType source_type;
/* Snapshots */
GstBuffer *last_buffer;
/*GStreamer elements */
GstElement *main_pipeline;
- GstElement *camerabin;
- GstElement *videosrc;
- GstElement *device_source;
- GstElement *videofilter;
- GstElement *audiosrc;
- GstElement *videoenc;
- GstElement *audioenc;
- GstElement *videomux;
+ GstElement *source_bin;
+ GstElement *source_decoder_bin;
+ GstElement *decoder_bin;
+ GstElement *preview_bin;
+ GstElement *encoder_bin;
+ GstElement *source;
+ GstElement *video_filter;
+ GstElement *video_enc;
+ GstElement *audio_enc;
+ GstElement *muxer;
+ GstElement *filesink;
+ GstElement* video_appsrc;
+ GstElement* audio_appsrc;
+ const gchar *source_element_name;
+
+ /* Recording */
+ gboolean is_recording;
+ gboolean closing_recording;
+ gboolean video_needs_keyframe_sync;
+ gboolean video_synced;
+ GstClockTime accum_recorded_ts;
+ GstClockTime last_accum_recorded_ts;
+ GstClockTime current_recording_start_ts;
+ GstClockTime last_video_buf_ts;
+ GstClockTime last_audio_buf_ts;
+ GMutex *recording_lock;
/*Overlay */
GstXOverlay *xoverlay; /* protect with lock */
@@ -175,169 +165,13 @@ static void gst_camera_capturer_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec);
static void gcc_element_msg_sync (GstBus * bus, GstMessage * msg,
gpointer data);
-static void gcc_update_interface_implementations (GstCameraCapturer * gcc);
static int gcc_get_video_stream_info (GstCameraCapturer * gcc);
+static void gcc_get_xoverlay (GstCameraCapturer * gcc);
G_DEFINE_TYPE (GstCameraCapturer, gst_camera_capturer, GTK_TYPE_EVENT_BOX);
-static void
-gst_camera_capturer_init (GstCameraCapturer * object)
-{
- GstCameraCapturerPrivate *priv;
- object->priv = priv =
- G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_CAMERA_CAPTURER,
- GstCameraCapturerPrivate);
-
- GTK_WIDGET_SET_FLAGS (GTK_WIDGET (object), GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (object), GTK_DOUBLE_BUFFERED);
-
- priv->zoom = 1.0;
- priv->output_height = 576;
- priv->output_width = 720;
- priv->output_fps_n = 25;
- priv->output_fps_d = 1;
- priv->audio_bitrate = 128;
- priv->video_bitrate = 5000;
- priv->last_buffer = NULL;
- priv->source_type = GST_CAMERA_CAPTURE_SOURCE_TYPE_NONE;
-
- priv->lock = g_mutex_new ();
-}
-
-void
-gst_camera_capturer_finalize (GObject * object)
-{
- GstCameraCapturer *gcc = (GstCameraCapturer *) object;
-
- GST_DEBUG_OBJECT (gcc, "Finalizing.");
- if (gcc->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 (gcc->priv->bus, TRUE);
-
- if (gcc->priv->sig_bus_async)
- g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_async);
-
- if (gcc->priv->sig_bus_sync)
- g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_sync);
-
- gst_object_unref (gcc->priv->bus);
- gcc->priv->bus = NULL;
- }
-
- if (gcc->priv->output_file) {
- g_free (gcc->priv->output_file);
- gcc->priv->output_file = NULL;
- }
-
- if (gcc->priv->device_id) {
- g_free (gcc->priv->device_id);
- gcc->priv->device_id = NULL;
- }
-
- if (gcc->priv->logo_pixbuf) {
- g_object_unref (gcc->priv->logo_pixbuf);
- gcc->priv->logo_pixbuf = NULL;
- }
-
- if (gcc->priv->interface_update_id) {
- g_source_remove (gcc->priv->interface_update_id);
- gcc->priv->interface_update_id = 0;
- }
-
- if (gcc->priv->last_buffer != NULL)
- gst_buffer_unref (gcc->priv->last_buffer);
-
- if (gcc->priv->main_pipeline != NULL
- && GST_IS_ELEMENT (gcc->priv->main_pipeline)) {
- gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
- gst_object_unref (gcc->priv->main_pipeline);
- gcc->priv->main_pipeline = NULL;
- }
-
- g_mutex_free (gcc->priv->lock);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_camera_capturer_apply_resolution (GstCameraCapturer * gcc)
-{
- GST_INFO_OBJECT (gcc, "Changed video resolution to %dx%d %d/%dfps",
- gcc->priv->output_width, gcc->priv->output_height,
- gcc->priv->output_fps_n, gcc->priv->output_fps_d);
-
- g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin),
- "set-video-resolution-fps", gcc->priv->output_width,
- gcc->priv->output_height, gcc->priv->output_fps_n,
- gcc->priv->output_fps_d);
-}
-
-static void
-gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
-{
- gcc->priv->video_bitrate = bitrate;
- if (gcc->priv->video_encoder_type == VIDEO_ENCODER_MPEG4 ||
- gcc->priv->video_encoder_type == VIDEO_ENCODER_XVID)
- g_object_set (gcc->priv->videoenc, "bitrate", bitrate * 1000, NULL);
- else
- g_object_set (gcc->priv->videoenc, "bitrate", gcc->priv->video_bitrate,
- NULL);
- GST_INFO_OBJECT (gcc, "Changed video bitrate to :\n%d",
- gcc->priv->video_bitrate);
-}
-
-static void
-gst_camera_capturer_set_audio_bit_rate (GstCameraCapturer * gcc, gint bitrate)
-{
-
- gcc->priv->audio_bitrate = bitrate;
- if (gcc->priv->audio_encoder_type == AUDIO_ENCODER_MP3)
- g_object_set (gcc->priv->audioenc, "bitrate", bitrate, NULL);
- else
- g_object_set (gcc->priv->audioenc, "bitrate", 1000 * bitrate, NULL);
- GST_INFO_OBJECT (gcc, "Changed audio bitrate to :\n%d",
- gcc->priv->audio_bitrate);
-
-}
-
-static void
-gst_camera_capturer_set_audio_enabled (GstCameraCapturer * gcc,
- gboolean enabled)
-{
- gint flags;
- gcc->priv->audio_enabled = enabled;
-
- g_object_get (gcc->priv->main_pipeline, "flags", &flags, NULL);
- if (!enabled) {
- flags &= ~GST_CAMERABIN_FLAG_DISABLE_AUDIO;
- GST_INFO_OBJECT (gcc, "Audio disabled");
- } else {
- flags |= GST_CAMERABIN_FLAG_DISABLE_AUDIO;
- GST_INFO_OBJECT (gcc, "Audio enabled");
- }
-}
-
-static void
-gst_camera_capturer_set_output_file (GstCameraCapturer * gcc,
- const gchar * file)
-{
- gcc->priv->output_file = g_strdup (file);
- g_object_set (gcc->priv->camerabin, "filename", file, NULL);
- GST_INFO_OBJECT (gcc, "Changed output filename to :\n%s", file);
-
-}
-
-static void
-gst_camera_capturer_set_device_id (GstCameraCapturer * gcc,
- const gchar * device_id)
-{
- gcc->priv->device_id = g_strdup (device_id);
- GST_INFO_OBJECT (gcc, "Changed device id/name to :\n%s", device_id);
-}
-
/***********************************
-*
+*
* GTK Widget
*
************************************/
@@ -649,8 +483,8 @@ gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
g_mutex_lock (gcc->priv->lock);
xoverlay = gcc->priv->xoverlay;
- if (xoverlay == NULL) {
- gcc_update_interface_implementations (gcc);
+ if (xoverlay == NULL && gcc->priv->preview_bin != NULL) {
+ gcc_get_xoverlay (gcc);
resize_video_window (gcc);
xoverlay = gcc->priv->xoverlay;
}
@@ -744,6 +578,142 @@ gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
return TRUE;
}
+/***********************************
+*
+* Class, Object and Properties
+*
+************************************/
+
+static void
+gst_camera_capturer_init (GstCameraCapturer * object)
+{
+ GstCameraCapturerPrivate *priv;
+ object->priv = priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_CAMERA_CAPTURER,
+ GstCameraCapturerPrivate);
+
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (object), GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (object), GTK_DOUBLE_BUFFERED);
+
+ priv->zoom = 1.0;
+ priv->output_height = 480;
+ priv->output_width = 640;
+ priv->audio_bitrate = 128;
+ priv->video_bitrate = 5000;
+ priv->last_buffer = NULL;
+ priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
+ priv->accum_recorded_ts = GST_CLOCK_TIME_NONE;
+ priv->last_accum_recorded_ts = GST_CLOCK_TIME_NONE;
+ priv->last_video_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->last_audio_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->is_recording = FALSE;
+ priv->recording_lock = g_mutex_new();
+
+ priv->video_encoder_type = VIDEO_ENCODER_VP8;
+ priv->audio_encoder_type = AUDIO_ENCODER_VORBIS;
+ priv->video_muxer_type = VIDEO_MUXER_WEBM;
+ priv->source_type = CAPTURE_SOURCE_TYPE_SYSTEM;
+
+ priv->lock = g_mutex_new ();
+}
+
+void
+gst_camera_capturer_finalize (GObject * object)
+{
+ GstCameraCapturer *gcc = (GstCameraCapturer *) object;
+
+ GST_DEBUG_OBJECT (gcc, "Finalizing.");
+ if (gcc->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 (gcc->priv->bus, TRUE);
+
+ if (gcc->priv->sig_bus_async)
+ g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_async);
+
+ if (gcc->priv->sig_bus_sync)
+ g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_sync);
+
+ gst_object_unref (gcc->priv->bus);
+ gcc->priv->bus = NULL;
+ }
+
+ if (gcc->priv->output_file) {
+ g_free (gcc->priv->output_file);
+ gcc->priv->output_file = NULL;
+ }
+
+ if (gcc->priv->device_id) {
+ g_free (gcc->priv->device_id);
+ gcc->priv->device_id = NULL;
+ }
+
+ if (gcc->priv->logo_pixbuf) {
+ g_object_unref (gcc->priv->logo_pixbuf);
+ gcc->priv->logo_pixbuf = NULL;
+ }
+
+ if (gcc->priv->interface_update_id) {
+ g_source_remove (gcc->priv->interface_update_id);
+ gcc->priv->interface_update_id = 0;
+ }
+
+ if (gcc->priv->last_buffer != NULL)
+ gst_buffer_unref (gcc->priv->last_buffer);
+
+ if (gcc->priv->main_pipeline != NULL
+ && GST_IS_ELEMENT (gcc->priv->main_pipeline)) {
+ gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+ gst_object_unref (gcc->priv->main_pipeline);
+ gcc->priv->main_pipeline = NULL;
+ }
+
+ g_mutex_free (gcc->priv->lock);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+ gcc->priv->video_bitrate = bitrate;
+ GST_INFO_OBJECT (gcc, "Changed video bitrate to: %d",
+ gcc->priv->video_bitrate);
+}
+
+static void
+gst_camera_capturer_set_audio_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+
+ gcc->priv->audio_bitrate = bitrate;
+ GST_INFO_OBJECT (gcc, "Changed audio bitrate to: %d",
+ gcc->priv->audio_bitrate);
+}
+
+static void
+gst_camera_capturer_set_audio_enabled (GstCameraCapturer * gcc,
+ gboolean enabled)
+{
+ gcc->priv->audio_enabled = enabled;
+ GST_INFO_OBJECT (gcc, "Audio is %s", enabled ? "enabled": "disabled");
+}
+
+static void
+gst_camera_capturer_set_output_file (GstCameraCapturer * gcc,
+ const gchar * file)
+{
+ gcc->priv->output_file = g_strdup (file);
+ GST_INFO_OBJECT (gcc, "Changed output filename to: %s", file);
+}
+
+static void
+gst_camera_capturer_set_device_id (GstCameraCapturer * gcc,
+ const gchar * device_id)
+{
+ gcc->priv->device_id = g_strdup (device_id);
+ GST_INFO_OBJECT (gcc, "Changed device id/name to: %s", gcc->priv->device_id);
+}
+
static void
gst_camera_capturer_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
@@ -755,11 +725,9 @@ gst_camera_capturer_set_property (GObject * object, guint property_id,
switch (property_id) {
case PROP_OUTPUT_HEIGHT:
gcc->priv->output_height = g_value_get_uint (value);
- gst_camera_capturer_apply_resolution (gcc);
break;
case PROP_OUTPUT_WIDTH:
gcc->priv->output_width = g_value_get_uint (value);
- gst_camera_capturer_apply_resolution (gcc);
break;
case PROP_VIDEO_BITRATE:
gst_camera_capturer_set_video_bit_rate (gcc, g_value_get_uint (value));
@@ -890,6 +858,12 @@ gst_camera_capturer_class_init (GstCameraCapturerClass * klass)
NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
}
+/***********************************
+*
+* GStreamer
+*
+************************************/
+
void
gst_camera_capturer_init_backend (int *argc, char ***argv)
{
@@ -925,314 +899,676 @@ gst_camera_capture_videosrc_buffer_probe (GstPad * pad, GstBuffer * buf,
}
static void
-cb_new_pad (GstElement * element, GstPad * pad, gpointer data)
+gst_camera_capturer_update_device_id (GstCameraCapturer *gcc)
{
- GstCaps *caps;
- const gchar *mime;
- GstElement *sink;
- GstBin *bin = GST_BIN (data);
+ const gchar *prop_name;
- caps = gst_pad_get_caps (pad);
+ if (!g_strcmp0 (gcc->priv->source_element_name, "dv1394src"))
+ prop_name = "guid";
+ else if (!g_strcmp0 (gcc->priv->source_element_name, "v4l2src"))
+ prop_name = "device";
+ else if (!g_strcmp0 (gcc->priv->source_element_name, "gsettingsvideosrc"))
+ prop_name = NULL;
+ else
+ prop_name = "device-name";
+
+ if (prop_name)
+ g_object_set(gcc->priv->source, prop_name, gcc->priv->device_id, NULL);
+}
+
+static void
+cb_new_pad (GstElement * element, GstPad * pad, GstCameraCapturer *gcc)
+{
+ GstCaps *caps;
+ const gchar *mime;
+ GstElement *sink = NULL;
+ GstPad *epad;
+ GstBin *bin = GST_BIN(gcc->priv->source_decoder_bin);
+
+ caps = gst_pad_get_caps_reffed (pad);
mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
if (g_strrstr (mime, "video")) {
- sink = gst_bin_get_by_name (bin, "source_video_sink");
- gst_pad_link (pad, gst_element_get_pad (sink, "sink"));
+ sink = gst_bin_get_by_name (bin, "video-pad");
+ }
+ if (g_strrstr (mime, "audio") && gcc->priv->audio_enabled) {
+ sink = gst_bin_get_by_name (bin, "audio-pad");
+ }
+
+ if (sink != NULL) {
+ epad = gst_element_get_static_pad(sink, "sink");
+ gst_pad_link (pad, epad);
+ gst_object_unref(epad);
+ }
+ gst_caps_unref(caps);
+}
+
+static void
+gst_camera_capturer_create_encoder_bin (GstCameraCapturer *gcc)
+{
+ GstElement *colorspace, *videoscale;
+ GstCaps *caps;
+ GstPad *v_sink_pad;
+ gchar *caps_str;
+
+ GST_INFO_OBJECT (gcc, "Creating encoder bin");
+ gcc->priv->encoder_bin = gst_bin_new ("encoder_bin");
+
+ colorspace = gst_element_factory_make("ffmpegcolorspace", NULL);
+ videoscale = gst_element_factory_make("videoscale", NULL);
+ gcc->priv->video_filter = gst_element_factory_make("capsfilter", NULL);
+ gcc->priv->filesink = gst_element_factory_make("filesink", NULL);
+
+ /* Set caps for the encoding resolution */
+ if (gcc->priv->output_width != 0 && gcc->priv->output_height != 0) {
+ caps_str = g_strdup_printf("video/x-raw-yuv, width=%d, height=%d",
+ gcc->priv->output_width, gcc->priv->output_height);
+ caps = gst_caps_from_string(caps_str);
+ g_object_set(gcc->priv->video_filter, "caps", caps, NULL);
+ gst_caps_unref(caps);
+ g_free(caps_str);
+ }
+
+ gst_bin_add_many(GST_BIN(gcc->priv->encoder_bin), videoscale,
+ colorspace, gcc->priv->video_filter, gcc->priv->video_enc,
+ gcc->priv->muxer, gcc->priv->filesink, NULL);
+
+ gst_element_link_many(videoscale, colorspace, gcc->priv->video_filter,
+ gcc->priv->video_enc, gcc->priv->muxer, NULL);
+ gst_element_link(gcc->priv->muxer, gcc->priv->filesink);
+
+ g_object_set (gcc->priv->filesink, "location", gcc->priv->output_file, NULL);
+
+ /* Create ghost pads */
+ v_sink_pad = gst_element_get_static_pad (videoscale, "sink");
+ gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("video", v_sink_pad));
+ gst_object_unref (GST_OBJECT (v_sink_pad));
+
+ if (gcc->priv->audio_enabled)
+ {
+ GstElement *audioconvert, *audioresample;
+ GstPad *a_sink_pad;
+
+ audioconvert = gst_element_factory_make("audioconvert", NULL);
+ audioresample = gst_element_factory_make("audioresample", NULL);
+
+ gst_bin_add_many(GST_BIN(gcc->priv->encoder_bin), audioconvert, audioresample,
+ audioresample, gcc->priv->audio_enc, NULL);
+
+ gst_element_link_many(audioconvert, audioresample, gcc->priv->audio_enc,
+ gcc->priv->muxer, NULL);
+
+ a_sink_pad = gst_element_get_static_pad (audioconvert, "sink");
+ gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("audio", a_sink_pad));
+ gst_object_unref (GST_OBJECT (a_sink_pad));
}
- if (g_strrstr (mime, "audio")) {
- /* Not implemented yet */
+
+ GST_INFO_OBJECT (gcc, "Encoder bin created successfully");
+}
+
+static void
+gst_camera_capturer_create_remuxer_bin (GstCameraCapturer *gcc)
+{
+ GstElement *muxer;
+ GstPad *v_sink_pad;
+
+ GST_INFO_OBJECT (gcc, "Creating remuxer bin");
+ gcc->priv->encoder_bin = gst_bin_new ("encoder_bin");
+ muxer = gst_element_factory_make("qtmux", NULL);
+ gcc->priv->filesink = gst_element_factory_make("filesink", NULL);
+ g_object_set (gcc->priv->filesink, "location", gcc->priv->output_file, NULL);
+
+ gst_bin_add_many(GST_BIN(gcc->priv->encoder_bin), muxer, gcc->priv->filesink, NULL);
+ gst_element_link(muxer, gcc->priv->filesink);
+
+ /* Create ghost pads */
+ v_sink_pad = gst_element_get_request_pad (muxer, "video_%d");
+ gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("video", v_sink_pad));
+ gst_object_unref (v_sink_pad);
+
+ if (gcc->priv->audio_enabled) {
+ GstPad *a_sink_pad;
+
+ /* Create ghost pads */
+ a_sink_pad = gst_element_get_request_pad (muxer, "audio_%d");
+ gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("audio", a_sink_pad));
+ gst_object_unref (GST_OBJECT (v_sink_pad));
}
}
-/* On linux GStreamer packages provided by distributions might still have the
- * dv1394src clock bug and the dvdemuxer buffers duration bug. That's why we
- * can't use decodebin2 and we need to force the use of ffdemux_dv */
static GstElement *
-gst_camera_capture_create_dv1394_source_bin (GstCameraCapturer * gcc)
-{
- GstElement *bin;
- GstElement *demuxer;
- GstElement *queue1;
- GstElement *decoder;
- GstElement *queue2;
- GstElement *deinterlacer;
- GstElement *colorspace;
- GstElement *videorate;
- GstElement *videoscale;
- GstPad *src_pad;
-
- bin = gst_bin_new ("videosource");
- gcc->priv->device_source =
- gst_element_factory_make (DVVIDEOSRC, "source_device");
- demuxer = gst_element_factory_make ("ffdemux_dv", NULL);
- queue1 = gst_element_factory_make ("queue", "source_video_sink");
- decoder = gst_element_factory_make ("ffdec_dvvideo", NULL);
- queue2 = gst_element_factory_make ("queue", NULL);
- deinterlacer = gst_element_factory_make ("ffdeinterlace", NULL);
- videorate = gst_element_factory_make ("videorate", NULL);
- colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
- videoscale = gst_element_factory_make ("videoscale", NULL);
-
- /* this property needs to be set before linking the element, where the device
- * id configured in get_caps() */
- g_object_set (G_OBJECT (gcc->priv->device_source), "guid",
- g_ascii_strtoull (gcc->priv->device_id, NULL, 0), NULL);
-
- gst_bin_add_many (GST_BIN (bin), gcc->priv->device_source, demuxer, queue1,
- decoder, queue2, deinterlacer, colorspace, videorate, videoscale, NULL);
- gst_element_link (gcc->priv->device_source, demuxer);
- gst_element_link_many (queue1, decoder, queue2, deinterlacer, videorate,
- colorspace, videoscale, NULL);
-
- g_signal_connect (demuxer, "pad-added", G_CALLBACK (cb_new_pad), bin);
+gst_camera_capturer_prepare_raw_source (GstCameraCapturer *gcc)
+{
+ GstElement *bin, *v_identity;
+ GstPad *video_pad, *src_pad;
+
+ GST_INFO_OBJECT (gcc, "Creating raw source");
+
+ gcc->priv->video_needs_keyframe_sync = FALSE;
+
+ gcc->priv->source_decoder_bin = gst_bin_new ("decoder");
+ bin = gcc->priv->source_decoder_bin;
+ v_identity = gst_element_factory_make ("identity", NULL);
+
+ gst_bin_add_many (GST_BIN (bin), v_identity, NULL);
/* add ghostpad */
- src_pad = gst_element_get_static_pad (videoscale, "src");
- gst_element_add_pad (bin, gst_ghost_pad_new ("src", src_pad));
+ video_pad = gst_element_get_static_pad (v_identity, "src");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("video", video_pad));
+ gst_object_unref (GST_OBJECT (video_pad));
+ src_pad = gst_element_get_static_pad (v_identity, "sink");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("sink", src_pad));
gst_object_unref (GST_OBJECT (src_pad));
+ gst_camera_capturer_create_encoder_bin(gcc);
+
return bin;
}
static GstElement *
-gst_camera_capture_create_dshow_source_bin (GstCameraCapturer * gcc)
-{
- GstElement *bin;
- GstElement *decoder;
- GstElement *deinterlacer;
- GstElement *colorspace;
- GstElement *videorate;
- GstElement *videoscale;
- GstPad *src_pad;
- GstCaps *source_caps;
-
- bin = gst_bin_new ("videosource");
- gcc->priv->device_source =
- gst_element_factory_make (DVVIDEOSRC, "source_device");
- decoder = gst_element_factory_make ("decodebin2", NULL);
- colorspace = gst_element_factory_make ("ffmpegcolorspace",
- "source_video_sink");
- deinterlacer = gst_element_factory_make ("ffdeinterlace", NULL);
- videorate = gst_element_factory_make ("videorate", NULL);
- videoscale = gst_element_factory_make ("videoscale", NULL);
-
- /* this property needs to be set before linking the element, where the device
- * id configured in get_caps() */
- g_object_set (G_OBJECT (gcc->priv->device_source), "device-name",
- gcc->priv->device_id, NULL);
-
- gst_bin_add_many (GST_BIN (bin), gcc->priv->device_source, decoder,
- colorspace, deinterlacer, videorate, videoscale, NULL);
- source_caps =
- gst_caps_from_string ("video/x-dv, systemstream=true;"
- "video/x-raw-rgb; video/x-raw-yuv");
- gst_element_link_filtered (gcc->priv->device_source, decoder, source_caps);
- gst_element_link_many (colorspace, deinterlacer, videorate, videoscale, NULL);
-
- g_signal_connect (decoder, "pad-added", G_CALLBACK (cb_new_pad), bin);
+gst_camera_capturer_prepare_dv_source (GstCameraCapturer *gcc)
+{
+ GstElement *bin, *decodebin, *deinterlacer;
+ GstPad *video_pad, *src_pad;
+
+ GST_INFO_OBJECT (gcc, "Creating dv source");
+
+ gcc->priv->video_needs_keyframe_sync = FALSE;
+
+ gcc->priv->source_decoder_bin = gst_bin_new ("decoder");
+ bin = gcc->priv->source_decoder_bin;
+ decodebin = gst_element_factory_make ("decodebin2", NULL);
+ deinterlacer = gst_element_factory_make ("ffdeinterlace", "video-pad");
+
+ gst_bin_add_many (GST_BIN (bin), decodebin, deinterlacer, NULL);
/* add ghostpad */
- src_pad = gst_element_get_static_pad (videoscale, "src");
- gst_element_add_pad (bin, gst_ghost_pad_new ("src", src_pad));
+ video_pad = gst_element_get_static_pad (deinterlacer, "src");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("video", video_pad));
+ gst_object_unref (GST_OBJECT (video_pad));
+ src_pad = gst_element_get_static_pad (decodebin, "sink");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("sink", src_pad));
gst_object_unref (GST_OBJECT (src_pad));
+ if (gcc->priv->audio_enabled) {
+ GstElement *audio;
+ GstPad *audio_pad;
+
+ audio = gst_element_factory_make ("identity", "audio-pad");
+
+ gst_bin_add_many (GST_BIN (bin), audio, NULL);
+
+ /* add ghostpad */
+ audio_pad = gst_element_get_static_pad (audio, "src");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("audio", audio_pad));
+ gst_object_unref (GST_OBJECT (audio_pad));
+ }
+
+ g_signal_connect (decodebin, "pad-added", G_CALLBACK (cb_new_pad), gcc);
+
+ gst_camera_capturer_create_encoder_bin(gcc);
+
return bin;
}
-gboolean
-gst_camera_capturer_set_source (GstCameraCapturer * gcc,
- GstCameraCaptureSourceType source_type, GError ** err)
+static GstElement *
+gst_camera_capturer_prepare_mpegts_source (GstCameraCapturer *gcc)
{
- GstPad *videosrcpad;
+ GstElement *bin, *demuxer, *video, *video_parser;
+ GstPad *video_pad, *src_pad;
- g_return_val_if_fail (gcc != NULL, FALSE);
- g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+ GST_INFO_OBJECT (gcc, "Creating mpegts source");
- if (gcc->priv->source_type == source_type)
- return TRUE;
- gcc->priv->source_type = source_type;
+ gcc->priv->video_needs_keyframe_sync = TRUE;
+ gcc->priv->video_synced = FALSE;
- switch (gcc->priv->source_type) {
- case GST_CAMERA_CAPTURE_SOURCE_TYPE_DV:
- {
- gcc->priv->videosrc = gst_camera_capture_create_dv1394_source_bin (gcc);
- /*gcc->priv->audiosrc = gcc->priv->videosrc; */
- break;
- }
- case GST_CAMERA_CAPTURE_SOURCE_TYPE_DSHOW:
- {
- gcc->priv->videosrc = gst_camera_capture_create_dshow_source_bin (gcc);
- /*gcc->priv->audiosrc = gcc->priv->videosrc; */
- break;
- }
- case GST_CAMERA_CAPTURE_SOURCE_TYPE_RAW:
- default:
- {
- gchar *videosrc = RAWVIDEOSRC;
-
-#if defined(OSTYPE_LINUX)
- GstElementFactory *fact = gst_element_factory_find(RAWVIDEOSRC);
- if (fact == NULL)
- videosrc = RAWVIDEOSRC_GCONF;
- else
- gst_object_unref (fact);
-#endif
+ /* We don't want to reencode, only remux */
+ gcc->priv->source_decoder_bin = gst_bin_new ("decoder");
+ bin = gcc->priv->source_decoder_bin;
+ demuxer = gst_element_factory_make ("mpegtsdemux", NULL);
+ video_parser = gst_element_factory_make ("h264parse", "video-pad");
+ video = gst_element_factory_make ("capsfilter", NULL);
+ g_object_set(video, "caps", gst_caps_from_string("video/x-h264, stream-format=avc, alignment=au"), NULL);
- gchar *bin =
- g_strdup_printf ("%s name=device_source ! videorate ! "
- "ffmpegcolorspace ! videoscale", videosrc);
- gcc->priv->videosrc = gst_parse_bin_from_description (bin, TRUE, err);
- gcc->priv->device_source =
- gst_bin_get_by_name (GST_BIN (gcc->priv->videosrc), "device_source");
- gcc->priv->audiosrc = gst_element_factory_make (AUDIOSRC, "audiosource");
- break;
- }
- }
- if (*err) {
- GST_ERROR_OBJECT (gcc, "Error changing source: %s", (*err)->message);
- return FALSE;
+ gst_bin_add_many (GST_BIN (bin), demuxer, video_parser, video, NULL);
+ gst_element_link(video_parser, video);
+
+ /* add ghostpad */
+ video_pad = gst_element_get_static_pad (video, "src");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("video", video_pad));
+ gst_object_unref (GST_OBJECT (video_pad));
+ src_pad = gst_element_get_static_pad (demuxer, "sink");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("sink", src_pad));
+ gst_object_unref (GST_OBJECT (src_pad));
+
+ if (gcc->priv->audio_enabled) {
+ GstElement *audio;
+ GstPad *audio_pad;
+
+ audio = gst_element_factory_make ("identity", "audio-pad");
+
+ gst_bin_add_many (GST_BIN (bin), audio, NULL);
+
+ /* add ghostpad */
+ audio_pad = gst_element_get_static_pad (audio, "src");
+ gst_element_add_pad (bin, gst_ghost_pad_new ("audio", audio_pad));
+ gst_object_unref (GST_OBJECT (audio_pad));
}
- g_object_set (gcc->priv->camerabin, "video-source", gcc->priv->videosrc,
- NULL);
+ g_signal_connect (demuxer, "pad-added", G_CALLBACK (cb_new_pad), gcc);
- /* Install pad probe to store the last buffer */
- videosrcpad = gst_element_get_pad (gcc->priv->videosrc, "src");
- gst_pad_add_buffer_probe (videosrcpad,
- G_CALLBACK (gst_camera_capture_videosrc_buffer_probe), gcc);
- return TRUE;
+ gst_camera_capturer_create_remuxer_bin(gcc);
+
+ return bin;
}
-GstCameraCapturer *
-gst_camera_capturer_new (gchar * filename, GError ** err)
+static gboolean
+gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
+ GstBuffer *prev_buf, gboolean is_video)
{
- GstCameraCapturer *gcc = NULL;
- gchar *plugin;
- gint flags = 0;
+ GstClockTime buf_ts, new_buf_ts, duration;
+ GstBuffer *enc_buf;
- gcc = g_object_new (GST_TYPE_CAMERA_CAPTURER, NULL);
+ g_mutex_lock(gcc->priv->recording_lock);
- gcc->priv->main_pipeline = gst_pipeline_new ("main_pipeline");
+ if (!gcc->priv->is_recording) {
+ /* Drop buffers if we are not recording */
+ GST_LOG_OBJECT (gcc, "Dropping buffer on %s pad", is_video ? "video": "audio");
+ goto done;
+ }
- if (!gcc->priv->main_pipeline) {
- plugin = "pipeline";
- goto missing_plugin;
+ /* If we are just remuxing, drop everything until we see a keyframe */
+ if (gcc->priv->video_needs_keyframe_sync && !gcc->priv->video_synced) {
+ if (is_video && !GST_BUFFER_FLAG_IS_SET(prev_buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
+ gcc->priv->video_synced = TRUE;
+ } else {
+ GST_LOG_OBJECT (gcc, "Waiting for a keyframe, "
+ "dropping buffer on %s pad", is_video ? "video": "audio");
+ goto done;
+ }
}
- /* Setup */
- GST_INFO_OBJECT (gcc, "Initializing camerabin");
- gcc->priv->camerabin = gst_element_factory_make ("camerabin", "camerabin");
- gst_bin_add (GST_BIN (gcc->priv->main_pipeline), gcc->priv->camerabin);
- if (!gcc->priv->camerabin) {
- plugin = "camerabin";
- goto missing_plugin;
+ enc_buf = gst_buffer_create_sub (prev_buf, 0, GST_BUFFER_SIZE(prev_buf));
+ buf_ts = GST_BUFFER_TIMESTAMP (prev_buf);
+ duration = GST_BUFFER_DURATION (prev_buf);
+ if (duration == GST_CLOCK_TIME_NONE)
+ duration = 0;
+
+ /* Check if it's the first buffer after starting or restarting the capture
+ * and update the timestamps accordingly */
+ if (G_UNLIKELY(gcc->priv->current_recording_start_ts == GST_CLOCK_TIME_NONE)) {
+ gcc->priv->current_recording_start_ts = buf_ts;
+ gcc->priv->last_accum_recorded_ts = gcc->priv->accum_recorded_ts;
+ GST_INFO_OBJECT (gcc, "Starting recording at %" GST_TIME_FORMAT,
+ GST_TIME_ARGS(gcc->priv->last_accum_recorded_ts));
}
- GST_INFO_OBJECT (gcc, "Setting capture mode to \"video\"");
- g_object_set (gcc->priv->camerabin, "mode", 1, NULL);
+ /* Clip buffers that are not in the segment */
+ if (buf_ts < gcc->priv->current_recording_start_ts) {
+ GST_WARNING_OBJECT (gcc, "Discarding buffer out of segment");
+ goto done;
+ }
- GST_INFO_OBJECT (gcc, "Disabling audio");
- flags = GST_CAMERABIN_FLAG_DISABLE_AUDIO;
-#ifdef WIN32
- flags |= GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION;
-#endif
- g_object_set (gcc->priv->camerabin, "flags", flags, NULL);
+ if (buf_ts != GST_CLOCK_TIME_NONE) {
+ /* Get the buffer timestamp with respect of the encoding time and not
+ * the playing time for a continous stream in the encoders input */
+ new_buf_ts = buf_ts - gcc->priv->current_recording_start_ts + gcc->priv->last_accum_recorded_ts;
- /* assume we're always called from the main Gtk+ GUI thread */
- gui_thread = g_thread_self ();
+ /* Store the last timestamp seen on this pad */
+ if (is_video)
+ gcc->priv->last_video_buf_ts = new_buf_ts;
+ else
+ gcc->priv->last_audio_buf_ts = new_buf_ts;
- /*Connect bus signals */
- GST_INFO_OBJECT (gcc, "Connecting bus signals");
- gcc->priv->bus = gst_element_get_bus (GST_ELEMENT (gcc->priv->main_pipeline));
- gst_bus_add_signal_watch (gcc->priv->bus);
- gcc->priv->sig_bus_async =
- g_signal_connect (gcc->priv->bus, "message",
- G_CALLBACK (gcc_bus_message_cb), gcc);
+ /* Update the highest encoded timestamp */
+ if (new_buf_ts + duration > gcc->priv->accum_recorded_ts)
+ gcc->priv->accum_recorded_ts = new_buf_ts + duration;
+ } else {
+ /* h264parse only sets the timestamp on the first buffer if a frame is
+ * split in several ones. Other parsers might do the same. We only set
+ * the last timestamp seen on the pad */
+ if (is_video)
+ new_buf_ts = gcc->priv->last_video_buf_ts;
+ else
+ new_buf_ts = gcc->priv->last_audio_buf_ts;
+ }
- /* we want to catch "prepare-xwindow-id" element messages synchronously */
- gst_bus_set_sync_handler (gcc->priv->bus, gst_bus_sync_signal_handler, gcc);
+ GST_BUFFER_TIMESTAMP (enc_buf) = new_buf_ts;
- gcc->priv->sig_bus_sync =
- g_signal_connect (gcc->priv->bus, "sync-message::element",
- G_CALLBACK (gcc_element_msg_sync), gcc);
+ GST_LOG_OBJECT(gcc, "Pushing %s frame to the encoder in ts:% " GST_TIME_FORMAT
+ " out ts: %" GST_TIME_FORMAT, is_video ? "video": "audio",
+ GST_TIME_ARGS(buf_ts), GST_TIME_ARGS(new_buf_ts));
- return gcc;
+ if (is_video)
+ gst_app_src_push_buffer(GST_APP_SRC(gcc->priv->video_appsrc), enc_buf);
+ else
+ gst_app_src_push_buffer(GST_APP_SRC(gcc->priv->audio_appsrc), enc_buf);
-/* Missing plugin */
-missing_plugin:
+done:
{
- g_set_error (err, GCC_ERROR, GST_ERROR_PLUGIN_LOAD,
- ("Failed to create a GStreamer element. "
- "The element \"%s\" is missing. "
- "Please check your GStreamer installation."), plugin);
- g_object_ref_sink (gcc);
- g_object_unref (gcc);
- return NULL;
+ g_mutex_unlock(gcc->priv->recording_lock);
+ return TRUE;
}
}
-void
-gst_camera_capturer_run (GstCameraCapturer * gcc)
+static gboolean
+gst_camera_capturer_audio_encoding_probe (GstPad *pad, GstBuffer *buf,
+ GstCameraCapturer *gcc)
{
- GError *err = NULL;
+ return gst_camera_capturer_encoding_retimestamper(gcc, buf, FALSE);
+}
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+static gboolean
+gst_camera_capturer_video_encoding_probe (GstPad *pad, GstBuffer *buf,
+ GstCameraCapturer *gcc)
+{
+ return gst_camera_capturer_encoding_retimestamper(gcc, buf, TRUE);
+}
- /* the source needs to be created before the 'device-is' is set
- * because dshowsrcwrapper can't change the device-name after
- * it has been linked for the first time */
- if (!gcc->priv->videosrc)
- gst_camera_capturer_set_source (gcc, gcc->priv->source_type, &err);
- gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_PLAYING);
+static void
+gst_camera_capturer_create_decoder_bin (GstCameraCapturer *gcc, GstElement *decoder_bin)
+{
+ /* decoder --> video_preview_queue
+ * |
+ * --> audio_preview_queue
+ *
+ * video_appsrc --> video_queue
+ * audio_appsrc --> audio_queue
+ */
+
+ GstElement *v_queue, *v_prev_queue;
+ GstPad *v_dec_pad, *v_queue_pad, *v_prev_queue_pad;
+ GstPad *dec_sink_pad;
+
+ GST_INFO_OBJECT(gcc, "Creating decoder bin");
+ /* Create elements */
+ gcc->priv->decoder_bin = gst_bin_new("decoder_bin");
+ v_queue = gst_element_factory_make("queue2", "video-queue");
+ gcc->priv->video_appsrc = gst_element_factory_make("appsrc", "video-appsrc");
+ v_prev_queue = gst_element_factory_make("queue2", "video-preview-queue");
+
+ g_object_set(v_queue, "max-size-time", 1 * GST_SECOND, NULL);
+ g_object_set(v_prev_queue, "max-size-bytes", 0, NULL);
+
+ gst_bin_add_many(GST_BIN(gcc->priv->decoder_bin), decoder_bin, v_queue,
+ gcc->priv->video_appsrc, v_prev_queue, NULL);
+
+ /* link decoder to the preview-queue */
+ v_dec_pad = gst_element_get_static_pad(decoder_bin, "video");
+ v_prev_queue_pad = gst_element_get_static_pad(v_prev_queue, "sink");
+ gst_pad_link(v_dec_pad, v_prev_queue_pad);
+ gst_object_unref(v_dec_pad);
+ gst_object_unref(v_prev_queue_pad);
+
+ /* Link appsrc */
+ gst_element_link (gcc->priv->video_appsrc, v_queue);
+
+ /* Create ghost pads */
+ v_queue_pad = gst_element_get_static_pad(v_queue, "src");
+ v_prev_queue_pad = gst_element_get_static_pad(v_prev_queue, "src");
+ dec_sink_pad = gst_element_get_static_pad(decoder_bin, "sink");
+ gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("video", v_queue_pad));
+ gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("video_preview", v_prev_queue_pad));
+ gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("sink", dec_sink_pad));
+ gst_object_unref(v_queue_pad);
+ gst_object_unref(v_prev_queue_pad);
+ gst_object_unref(dec_sink_pad);
+
+ /* Add pad probes for the encoding branch */
+ v_prev_queue_pad = gst_element_get_static_pad(v_prev_queue, "src");
+ gst_pad_add_buffer_probe(v_prev_queue_pad, (GCallback) gst_camera_capturer_video_encoding_probe, gcc);
+ gst_object_unref(v_prev_queue_pad);
+
+ if (gcc->priv->audio_enabled) {
+ GstElement *a_queue, *a_prev_queue;
+ GstPad *a_dec_pad, *a_queue_pad, *a_prev_queue_pad;
+
+ /* Create elements */
+ gcc->priv->audio_appsrc = gst_element_factory_make("appsrc", "video-appsrc");
+ a_queue = gst_element_factory_make("queue2", "audio-queue");
+ a_prev_queue = gst_element_factory_make("queue2", "audio-preview-queue");
+
+ g_object_set(a_queue, "max-size-time", 1 * GST_SECOND, NULL);
+
+ gst_bin_add_many(GST_BIN(gcc->priv->decoder_bin), gcc->priv->audio_appsrc, a_queue,
+ a_prev_queue, NULL);
+
+ /* Link appsrc to the queue */
+ gst_element_link(gcc->priv->audio_appsrc, a_queue);
+
+ /* link decoder to the queue */
+ a_dec_pad = gst_element_get_static_pad(decoder_bin, "audio");
+ a_prev_queue_pad = gst_element_get_static_pad(a_prev_queue, "sink");
+ gst_pad_link(a_dec_pad, a_prev_queue_pad);
+ gst_object_unref(a_dec_pad);
+ gst_object_unref(a_prev_queue_pad);
+
+ /* Create ghost pads */
+ a_queue_pad = gst_element_get_static_pad(a_queue, "src");
+ a_prev_queue_pad = gst_element_get_static_pad(a_prev_queue, "src");
+ gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("audio", a_queue_pad));
+ gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("audio_preview", a_prev_queue_pad));
+ gst_object_unref(a_queue_pad);
+ gst_object_unref(a_prev_queue_pad);
+
+ /* Add pad probes for the encoding branch */
+ a_prev_queue_pad = gst_element_get_static_pad(a_prev_queue, "src");
+ gst_pad_add_buffer_probe(a_prev_queue_pad, (GCallback) gst_camera_capturer_audio_encoding_probe, gcc);
+ gst_object_unref(a_prev_queue_pad);
+ }
}
-void
-gst_camera_capturer_close (GstCameraCapturer * gcc)
+static void
+gst_camera_capturer_link_encoder_bin (GstCameraCapturer *gcc)
{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+ GstPad *v_dec_pad, *v_enc_pad;
- gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+ GST_INFO_OBJECT(gcc, "Linking encoder bin");
+
+ gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->encoder_bin);
+
+ v_dec_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "video");
+ v_enc_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "video");
+ gst_pad_link(v_dec_pad, v_enc_pad);
+ gst_object_unref(v_dec_pad);
+ gst_object_unref(v_enc_pad);
+
+ if (gcc->priv->audio_enabled) {
+ GstPad *a_dec_pad, *a_enc_pad;
+
+ a_dec_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "audio");
+ a_enc_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "audio");
+ gst_pad_link(a_dec_pad, a_enc_pad);
+ gst_object_unref(a_dec_pad);
+ gst_object_unref(a_enc_pad);
+ }
+
+ gst_element_set_state(gcc->priv->encoder_bin, GST_STATE_PLAYING);
}
-void
-gst_camera_capturer_start (GstCameraCapturer * gcc)
+static void
+gst_camera_capturer_link_preview (GstCameraCapturer *gcc)
{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+ GstPad *v_dec_prev_pad, *v_prev_pad;
+
+ GST_INFO_OBJECT(gcc, "Linking preview bin");
+
+ gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->decoder_bin);
+
+ gst_element_link(gcc->priv->source_bin, gcc->priv->decoder_bin);
+
+ v_dec_prev_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "video_preview");
+ v_prev_pad = gst_element_get_static_pad(gcc->priv->preview_bin, "video");
+
+ gst_pad_link(v_dec_prev_pad, v_prev_pad);
+
+ gst_object_unref(v_dec_prev_pad);
+ gst_object_unref(v_prev_pad);
+
+ if (gcc->priv->audio_enabled) {
+ GstPad *a_dec_prev_pad, *a_prev_pad;
- g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-start", 0,
- 0);
+ a_dec_prev_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "audio_preview");
+ a_prev_pad = gst_element_get_static_pad(gcc->priv->preview_bin, "audio");
+
+ gst_pad_link(a_dec_prev_pad, a_prev_pad);
+
+ gst_object_unref(a_dec_prev_pad);
+ gst_object_unref(a_prev_pad);
+ }
+ gst_element_set_state(gcc->priv->decoder_bin, GST_STATE_PLAYING);
}
-void
-gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc)
+static void
+cb_new_prev_pad (GstElement * element, GstPad * pad, GstElement *bin)
{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+ GstPad *sink_pad;
- g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-pause", 0,
- 0);
+ sink_pad = gst_element_get_static_pad(bin, "sink");
+ gst_pad_link(pad, sink_pad);
+ gst_object_unref(sink_pad);
}
-void
-gst_camera_capturer_stop (GstCameraCapturer * gcc)
+static void
+gst_camera_capturer_create_preview(GstCameraCapturer *gcc)
{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+ GstElement *v_decoder, *video_bin;
+ GstPad *video_pad;
-#ifdef WIN32
- //On windows we can't handle device disconnections until dshowvideosrc
- //supports it. When a device is disconnected, the source is locked
- //in ::create(), blocking the streaming thread. We need to change its
- //state to null, this way camerabin doesn't block in ::do_stop().
- gst_element_set_state(gcc->priv->device_source, GST_STATE_NULL);
-#endif
- g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-stop", 0, 0);
+ v_decoder = gst_element_factory_make("decodebin2", "preview-decoder");
+
+ video_bin = gst_parse_bin_from_description(
+ "videoscale ! ffmpegcolorspace ! autovideosink name=videosink", TRUE, NULL);
+
+ gcc->priv->preview_bin = gst_bin_new("preview_bin");
+ gst_bin_add_many (GST_BIN(gcc->priv->preview_bin), v_decoder, video_bin, NULL);
+
+ g_signal_connect (v_decoder, "pad-added", G_CALLBACK (cb_new_prev_pad), video_bin);
+
+ /* Create ghost pads */
+ video_pad = gst_element_get_static_pad (v_decoder, "sink");
+ gst_element_add_pad (gcc->priv->preview_bin, gst_ghost_pad_new ("video", video_pad));
+ gst_object_unref (GST_OBJECT (video_pad));
+
+ if (gcc->priv->audio_enabled) {
+ GstElement *a_decoder, *audio_bin;
+ GstPad *audio_pad;
+
+ a_decoder = gst_element_factory_make("decodebin2", NULL);
+
+ audio_bin = gst_parse_bin_from_description(
+ "audioconvert ! audioresample ! autoaudiosink name=audiosink", TRUE, NULL);
+
+ gst_bin_add_many (GST_BIN(gcc->priv->preview_bin), a_decoder, audio_bin, NULL);
+
+ g_signal_connect (a_decoder, "pad-added", G_CALLBACK (cb_new_prev_pad), audio_bin);
+
+ /* Create ghost pads */
+ audio_pad = gst_element_get_static_pad (a_decoder, "sink");
+ gst_element_add_pad (gcc->priv->preview_bin, gst_ghost_pad_new ("audio", audio_pad));
+ gst_object_unref (GST_OBJECT (audio_pad));
+ }
+
+ gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->preview_bin);
+ gst_element_set_state(gcc->priv->preview_bin, GST_STATE_PLAYING);
}
-gboolean
-gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc,
+static gboolean
+gst_camera_capturer_have_type_cb (GstElement *typefind, guint prob,
+ GstCaps *caps, GstCameraCapturer *gcc)
+{
+ GstCaps *media_caps;
+ GstElement *decoder_bin = NULL;
+
+ GST_INFO_OBJECT (gcc, "Found type with caps %s", gst_caps_to_string(caps));
+
+ /* Check for DV streams */
+ media_caps = gst_caps_from_string("video/x-dv, systemstream=true");
+
+ if (gst_caps_can_intersect(caps, media_caps)) {
+ decoder_bin = gst_camera_capturer_prepare_dv_source(gcc);
+ gst_caps_unref(media_caps);
+ }
+
+ /* Check for MPEG-TS streams */
+ media_caps = gst_caps_from_string("video/mpegts");
+ if (gst_caps_can_intersect(caps, media_caps)) {
+ decoder_bin = gst_camera_capturer_prepare_mpegts_source(gcc);
+ gst_caps_unref(media_caps);
+ }
+
+ /* Check for Raw streams */
+ media_caps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
+ if (gst_caps_can_intersect(caps, media_caps)) {
+ gcc->priv->audio_enabled = FALSE;
+ decoder_bin = gst_camera_capturer_prepare_raw_source(gcc);
+ gst_caps_unref(media_caps);
+ }
+
+ if (decoder_bin != NULL) {
+ gst_camera_capturer_create_decoder_bin(gcc, decoder_bin);
+ gst_camera_capturer_create_preview(gcc);
+
+ gst_camera_capturer_link_preview(gcc);
+ gst_element_set_state(gcc->priv->main_pipeline, GST_STATE_PLAYING);
+ } else {
+ /* FIXME: post error */
+ }
+ return TRUE;
+}
+
+static gboolean
+gst_camera_capturer_create_video_source (GstCameraCapturer * gcc,
+ CaptureSourceType type, GError ** err)
+{
+ GstElement *typefind;
+ const gchar *source_desc = "";
+ gchar *source_str;
+
+ g_return_val_if_fail (gcc != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+
+ switch (type) {
+ case CAPTURE_SOURCE_TYPE_DV:
+ GST_INFO_OBJECT(gcc, "Creating dv video source");
+ source_desc = DVVIDEOSRC;
+ gcc->priv->source_element_name = source_desc;
+ break;
+ case CAPTURE_SOURCE_TYPE_SYSTEM:
+ GST_INFO_OBJECT(gcc, "Creating system video source");
+ source_desc = SYSVIDEOSRC;
+ gcc->priv->source_element_name = source_desc;
+ //source_desc = "filesrc location=/home/andoni/test.ts";
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ source_str = g_strdup_printf("%s name=source ! typefind name=typefind", source_desc);
+ gcc->priv->source_bin = gst_parse_bin_from_description(source_str, TRUE, NULL);
+ g_free(source_str);
+ if (!gcc->priv->source_bin) {
+ g_set_error (err,
+ GCC_ERROR,
+ GST_ERROR_PLUGIN_LOAD,
+ "Failed to create the %s element. "
+ "Please check your GStreamer installation.", source_desc);
+ return FALSE;
+ }
+
+ gcc->priv->source = gst_bin_get_by_name (GST_BIN(gcc->priv->source_bin), "source");
+ typefind = gst_bin_get_by_name (GST_BIN(gcc->priv->source_bin), "typefind");
+ g_signal_connect (typefind, "have-type",
+ G_CALLBACK (gst_camera_capturer_have_type_cb), gcc);
+
+ gst_camera_capturer_update_device_id(gcc);
+
+ GST_INFO_OBJECT(gcc, "Created video source %s", source_desc);
+
+ return TRUE;
+}
+
+static gboolean
+gst_camera_capturer_create_video_encoder (GstCameraCapturer * gcc,
VideoEncoderType type, GError ** err)
{
gchar *name = NULL;
@@ -1242,63 +1578,70 @@ gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc,
switch (type) {
case VIDEO_ENCODER_MPEG4:
- gcc->priv->videoenc =
+ gcc->priv->video_enc =
gst_element_factory_make ("ffenc_mpeg4", "video-encoder");
- g_object_set (gcc->priv->videoenc, "pass", 512,
+ g_object_set (gcc->priv->video_enc, "pass", 512,
"max-key-interval", -1, NULL);
name = "FFmpeg mpeg4 video encoder";
break;
case VIDEO_ENCODER_XVID:
- gcc->priv->videoenc =
+ gcc->priv->video_enc =
gst_element_factory_make ("xvidenc", "video-encoder");
- g_object_set (gcc->priv->videoenc, "pass", 1,
+ g_object_set (gcc->priv->video_enc, "pass", 1,
"profile", 146, "max-key-interval", -1, NULL);
name = "Xvid video encoder";
break;
case VIDEO_ENCODER_H264:
- gcc->priv->videoenc =
+ gcc->priv->video_enc =
gst_element_factory_make ("x264enc", "video-encoder");
- g_object_set (gcc->priv->videoenc, "key-int-max", 25, "pass", 17,
+ g_object_set (gcc->priv->video_enc, "key-int-max", 25, "pass", 17,
"speed-preset", 3, NULL);
name = "X264 video encoder";
break;
case VIDEO_ENCODER_THEORA:
- gcc->priv->videoenc =
+ gcc->priv->video_enc =
gst_element_factory_make ("theoraenc", "video-encoder");
- g_object_set (gcc->priv->videoenc, "keyframe-auto", FALSE,
+ g_object_set (gcc->priv->video_enc, "keyframe-auto", FALSE,
"keyframe-force", 25, NULL);
name = "Theora video encoder";
break;
case VIDEO_ENCODER_VP8:
default:
- gcc->priv->videoenc =
+ gcc->priv->video_enc =
gst_element_factory_make ("vp8enc", "video-encoder");
- g_object_set (gcc->priv->videoenc, "speed", 2, "threads", 8,
+ g_object_set (gcc->priv->video_enc, "speed", 2, "threads", 8,
"max-keyframe-distance", 25, NULL);
name = "VP8 video encoder";
break;
}
- if (!gcc->priv->videoenc) {
+ if (!gcc->priv->video_enc) {
g_set_error (err,
GCC_ERROR,
GST_ERROR_PLUGIN_LOAD,
"Failed to create the %s element. "
"Please check your GStreamer installation.", name);
- } else {
- g_object_set (gcc->priv->camerabin, "video-encoder", gcc->priv->videoenc,
- NULL);
- gcc->priv->video_encoder_type = type;
+ return FALSE;
}
+
+ if (gcc->priv->video_encoder_type == VIDEO_ENCODER_MPEG4 ||
+ gcc->priv->video_encoder_type == VIDEO_ENCODER_XVID)
+ g_object_set (gcc->priv->video_enc, "bitrate", gcc->priv->video_bitrate * 1000, NULL);
+ else
+ g_object_set (gcc->priv->video_enc, "bitrate", gcc->priv->video_bitrate,
+ NULL);
+
+ GST_INFO_OBJECT(gcc, "Video encoder %s created", name);
+ gcc->priv->video_encoder_type = type;
return TRUE;
}
-gboolean
-gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc,
+static gboolean
+gst_camera_capturer_create_audio_encoder (GstCameraCapturer * gcc,
AudioEncoderType type, GError ** err)
{
gchar *name = NULL;
@@ -1308,42 +1651,47 @@ gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc,
switch (type) {
case AUDIO_ENCODER_MP3:
- gcc->priv->audioenc =
+ gcc->priv->audio_enc =
gst_element_factory_make ("lamemp3enc", "audio-encoder");
- g_object_set (gcc->priv->audioenc, "target", 0, NULL);
+ g_object_set (gcc->priv->audio_enc, "target", 0, NULL);
name = "Mp3 audio encoder";
break;
case AUDIO_ENCODER_AAC:
- gcc->priv->audioenc = gst_element_factory_make ("faac", "audio-encoder");
+ gcc->priv->audio_enc = gst_element_factory_make ("faac", "audio-encoder");
name = "AAC audio encoder";
break;
case AUDIO_ENCODER_VORBIS:
default:
- gcc->priv->audioenc =
+ gcc->priv->audio_enc =
gst_element_factory_make ("vorbisenc", "audio-encoder");
name = "Vorbis audio encoder";
break;
}
- if (!gcc->priv->audioenc) {
+ if (!gcc->priv->audio_enc) {
g_set_error (err,
GCC_ERROR,
GST_ERROR_PLUGIN_LOAD,
"Failed to create the %s element. "
"Please check your GStreamer installation.", name);
- } else {
- g_object_set (gcc->priv->camerabin, "audio-encoder", gcc->priv->audioenc,
- NULL);
- gcc->priv->audio_encoder_type = type;
+ return FALSE;
}
+ if (gcc->priv->audio_encoder_type == AUDIO_ENCODER_MP3)
+ g_object_set (gcc->priv->audio_enc, "bitrate", gcc->priv->audio_bitrate, NULL);
+ else
+ g_object_set (gcc->priv->audio_enc, "bitrate", 1000 * gcc->priv->audio_bitrate, NULL);
+
+ GST_INFO_OBJECT(gcc, "Audio encoder %s created", name);
+
+ gcc->priv->audio_encoder_type = type;
return TRUE;
}
-gboolean
-gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc,
+static gboolean
+gst_camera_capturer_create_video_muxer (GstCameraCapturer * gcc,
VideoMuxerType type, GError ** err)
{
gchar *name = NULL;
@@ -1354,43 +1702,90 @@ gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc,
switch (type) {
case VIDEO_MUXER_OGG:
name = "OGG muxer";
- gcc->priv->videomux = gst_element_factory_make ("oggmux", "video-muxer");
+ gcc->priv->muxer = gst_element_factory_make ("oggmux", "video-muxer");
break;
case VIDEO_MUXER_AVI:
name = "AVI muxer";
- gcc->priv->videomux = gst_element_factory_make ("avimux", "video-muxer");
+ gcc->priv->muxer = gst_element_factory_make ("avimux", "video-muxer");
break;
case VIDEO_MUXER_MATROSKA:
name = "Matroska muxer";
- gcc->priv->videomux =
+ gcc->priv->muxer =
gst_element_factory_make ("matroskamux", "video-muxer");
break;
case VIDEO_MUXER_MP4:
name = "MP4 muxer";
- gcc->priv->videomux = gst_element_factory_make ("qtmux", "video-muxer");
+ gcc->priv->muxer = gst_element_factory_make ("qtmux", "video-muxer");
break;
case VIDEO_MUXER_WEBM:
default:
name = "WebM muxer";
- gcc->priv->videomux = gst_element_factory_make ("webmmux", "video-muxer");
+ gcc->priv->muxer = gst_element_factory_make ("webmmux", "video-muxer");
break;
}
- if (!gcc->priv->videomux) {
+ if (!gcc->priv->muxer) {
g_set_error (err,
GCC_ERROR,
GST_ERROR_PLUGIN_LOAD,
"Failed to create the %s element. "
"Please check your GStreamer installation.", name);
- } else {
- g_object_set (gcc->priv->camerabin, "video-muxer", gcc->priv->videomux,
- NULL);
}
+ GST_INFO_OBJECT(gcc, "Muxer %s created", name);
+ gcc->priv->video_muxer_type = type;
return TRUE;
}
static void
+gst_camera_capturer_initialize (GstCameraCapturer *gcc)
+{
+ GError *err= NULL;
+
+ GST_INFO_OBJECT (gcc, "Initializing encoders");
+ if (!gst_camera_capturer_create_video_encoder(gcc,
+ gcc->priv->video_encoder_type, &err))
+ goto missing_plugin;
+ if (!gst_camera_capturer_create_audio_encoder(gcc,
+ gcc->priv->audio_encoder_type, &err))
+ goto missing_plugin;
+ if (!gst_camera_capturer_create_video_muxer(gcc,
+ gcc->priv->video_muxer_type, &err))
+ goto missing_plugin;
+
+ GST_INFO_OBJECT (gcc, "Initializing source");
+ if (!gst_camera_capturer_create_video_source(gcc,
+ gcc->priv->source_type, &err))
+ goto missing_plugin;
+
+ /* add the source element */
+ gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->source_bin);
+ return;
+
+missing_plugin:
+ g_signal_emit (gcc, gcc_signals[SIGNAL_ERROR], 0, err->message);
+ g_error_free (err);
+}
+
+static void
+gcc_encoder_send_event (GstCameraCapturer *gcc, GstEvent *event)
+{
+ GstPad *video_pad, *audio_pad;
+
+ if (gcc->priv->audio_enabled) {
+ gst_event_ref(event);
+ audio_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "audio");
+ gst_pad_send_event(audio_pad, event);
+ gst_object_unref(audio_pad);
+ }
+
+ video_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "video");
+ gst_pad_send_event(video_pad, event);
+ gst_object_unref(video_pad);
+
+}
+
+static void
gcc_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
{
GstCameraCapturer *gcc = (GstCameraCapturer *) data;
@@ -1452,7 +1847,7 @@ gcc_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
gint device_change = 0;
/* We only care about messages sent by the device source */
- if (GST_MESSAGE_SRC (message) != GST_OBJECT (gcc->priv->device_source))
+ if (GST_MESSAGE_SRC (message) != GST_OBJECT (gcc->priv->source))
break;
s = gst_message_get_structure (message);
@@ -1503,34 +1898,14 @@ gcc_error_msg (GstCameraCapturer * gcc, GstMessage * msg)
g_free (dbg);
}
-static gboolean
-gcc_update_interfaces_delayed (GstCameraCapturer * gcc)
-{
- GST_DEBUG_OBJECT (gcc, "Delayed updating interface implementations");
- g_mutex_lock (gcc->priv->lock);
- gcc_update_interface_implementations (gcc);
- gcc->priv->interface_update_id = 0;
- g_mutex_unlock (gcc->priv->lock);
-
- return FALSE;
-}
-
static void
-gcc_update_interface_implementations (GstCameraCapturer * gcc)
+gcc_get_xoverlay (GstCameraCapturer * gcc)
{
GstElement *element = NULL;
- if (g_thread_self () != gui_thread) {
- if (gcc->priv->interface_update_id)
- g_source_remove (gcc->priv->interface_update_id);
- gcc->priv->interface_update_id =
- g_idle_add ((GSourceFunc) gcc_update_interfaces_delayed, gcc);
- return;
- }
-
- GST_INFO_OBJECT (gcc, "Retrieving xoverlay from bin ...");
- element = gst_bin_get_by_interface (GST_BIN (gcc->priv->camerabin),
+ GST_DEBUG_OBJECT (gcc, "Retrieving xoverlay from bin ...");
+ element = gst_bin_get_by_interface (GST_BIN (gcc->priv->preview_bin),
GST_TYPE_X_OVERLAY);
if (GST_IS_X_OVERLAY (element)) {
@@ -1554,7 +1929,7 @@ gcc_element_msg_sync (GstBus * bus, GstMessage * msg, gpointer data)
* chance to set it before the video sink will create its own window */
if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) {
g_mutex_lock (gcc->priv->lock);
- gcc_update_interface_implementations (gcc);
+ gcc_get_xoverlay (gcc);
g_mutex_unlock (gcc->priv->lock);
if (gcc->priv->xoverlay == NULL) {
@@ -1577,7 +1952,7 @@ gcc_get_video_stream_info (GstCameraCapturer * gcc)
GstCaps *caps;
GstStructure *s;
- sourcepad = gst_element_get_pad (gcc->priv->videosrc, "src");
+ sourcepad = gst_element_get_pad (gcc->priv->source_bin, "src");
caps = gst_pad_get_negotiated_caps (sourcepad);
if (!(caps)) {
@@ -1601,6 +1976,12 @@ gcc_get_video_stream_info (GstCameraCapturer * gcc)
return 1;
}
+/*****************************************************
+ *
+ * Device Probe
+ *
+ * **************************************************/
+
GList *
gst_camera_capturer_enum_devices (gchar * device_name)
{
@@ -1661,12 +2042,108 @@ gst_camera_capturer_enum_audio_devices (void)
return gst_camera_capturer_enum_devices (AUDIOSRC);
}
+/*******************************************
+ *
+ * Public methods
+ *
+ * ****************************************/
+
+void
+gst_camera_capturer_run (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gst_camera_capturer_initialize (gcc);
+ gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_PLAYING);
+}
+
+void
+gst_camera_capturer_close (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+ gst_element_get_state (gcc->priv->main_pipeline, NULL, NULL, -1);
+}
+
+void
+gst_camera_capturer_start (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ GST_INFO_OBJECT(gcc, "Started capture");
+ g_mutex_lock(gcc->priv->recording_lock);
+ if (!gcc->priv->is_recording && gcc->priv->accum_recorded_ts == GST_CLOCK_TIME_NONE) {
+ gcc->priv->accum_recorded_ts = 0;
+ gcc->priv->is_recording = TRUE;
+ gst_camera_capturer_link_encoder_bin (gcc);
+ }
+ g_mutex_unlock(gcc->priv->recording_lock);
+}
+
+void
+gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ g_mutex_lock(gcc->priv->recording_lock);
+ if (!gcc->priv->is_recording) {
+ gcc->priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
+ gcc->priv->is_recording = TRUE;
+ } else {
+ gcc->priv->is_recording = FALSE;
+ gcc->priv->video_synced = FALSE;
+ }
+ g_mutex_unlock(gcc->priv->recording_lock);
+
+ GST_INFO_OBJECT(gcc, "Capture state changed to %s", gcc->priv->is_recording ? "recording": "paused");
+}
+
+void
+gst_camera_capturer_set_source (GstCameraCapturer * gcc, CaptureSourceType source)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gcc->priv->source_type = source;
+}
+
+void
+gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc, VideoEncoderType encoder)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gcc->priv->video_encoder_type = encoder;
+}
+
+void
+gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc, AudioEncoderType encoder)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gcc->priv->audio_encoder_type = encoder;
+}
+
+void
+gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc, VideoMuxerType muxer)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gcc->priv->video_muxer_type = muxer;
+}
+
gboolean
gst_camera_capturer_can_get_frames (GstCameraCapturer * gcc, GError ** error)
{
g_return_val_if_fail (gcc != NULL, FALSE);
g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
- g_return_val_if_fail (GST_IS_ELEMENT (gcc->priv->camerabin), FALSE);
/* check for video */
if (!gcc->priv->media_has_video) {
@@ -1702,9 +2179,8 @@ gst_camera_capturer_get_current_frame (GstCameraCapturer * gcc)
g_return_val_if_fail (gcc != NULL, NULL);
g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), NULL);
- g_return_val_if_fail (GST_IS_ELEMENT (gcc->priv->camerabin), NULL);
- gst_element_get_state (gcc->priv->camerabin, NULL, NULL, -1);
+ gst_element_get_state (gcc->priv->main_pipeline, NULL, NULL, -1);
/* no video info */
if (!gcc->priv->video_width || !gcc->priv->video_height) {
@@ -1791,3 +2267,81 @@ gst_camera_capturer_get_current_frame (GstCameraCapturer * gcc)
return pixbuf;
}
+
+
+void
+gst_camera_capturer_stop (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+#ifdef WIN32
+ //On windows we can't handle device disconnections until dshowvideosrc
+ //supports it. When a device is disconnected, the source is locked
+ //in ::create(), blocking the streaming thread. We need to change its
+ //state to null, this way camerabin doesn't block in ::do_stop().
+ gst_element_set_state(gcc->priv->device_source, GST_STATE_NULL);
+#endif
+
+ GST_INFO_OBJECT(gcc, "Closing capture");
+ g_mutex_lock(gcc->priv->recording_lock);
+ gcc->priv->closing_recording = TRUE;
+ gcc->priv->is_recording = FALSE;
+ g_mutex_unlock(gcc->priv->recording_lock);
+
+ gcc_encoder_send_event(gcc, gst_event_new_eos());
+}
+
+GstCameraCapturer *
+gst_camera_capturer_new (gchar * filename, GError ** err)
+{
+ GstCameraCapturer *gcc = NULL;
+
+#ifndef GST_DISABLE_GST_INFO
+ if (_cesarplayer_gst_debug_cat == NULL) {
+ GST_DEBUG_CATEGORY_INIT (_cesarplayer_gst_debug_cat, "longomatch", 0,
+ "LongoMatch GStreamer Backend");
+ }
+#endif
+
+ gcc = g_object_new (GST_TYPE_CAMERA_CAPTURER, NULL);
+
+ gcc->priv->main_pipeline = gst_pipeline_new ("main_pipeline");
+
+ if (!gcc->priv->main_pipeline) {
+ g_set_error (err,
+ GCC_ERROR,
+ GST_ERROR_PLUGIN_LOAD,
+ "Failed to create the pipeline element. "
+ "Please check your GStreamer installation.");
+ goto missing_plugin;
+ }
+
+ /* assume we're always called from the main Gtk+ GUI thread */
+ gui_thread = g_thread_self ();
+
+ /*Connect bus signals */
+ GST_INFO_OBJECT (gcc, "Connecting bus signals");
+ gcc->priv->bus = gst_element_get_bus (GST_ELEMENT (gcc->priv->main_pipeline));
+ gst_bus_add_signal_watch (gcc->priv->bus);
+ gcc->priv->sig_bus_async =
+ g_signal_connect (gcc->priv->bus, "message",
+ G_CALLBACK (gcc_bus_message_cb), gcc);
+
+ /* we want to catch "prepare-xwindow-id" element messages synchronously */
+ gst_bus_set_sync_handler (gcc->priv->bus, gst_bus_sync_signal_handler, gcc);
+
+ gcc->priv->sig_bus_sync =
+ g_signal_connect (gcc->priv->bus, "sync-message::element",
+ G_CALLBACK (gcc_element_msg_sync), gcc);
+
+ return gcc;
+
+/* Missing plugin */
+missing_plugin:
+ {
+ g_object_ref_sink (gcc);
+ g_object_unref (gcc);
+ return NULL;
+ }
+}
diff --git a/libcesarplayer/gst-camera-capturer.h b/libcesarplayer/gst-camera-capturer.h
index 0e83bb5..b2ca89f 100644
--- a/libcesarplayer/gst-camera-capturer.h
+++ b/libcesarplayer/gst-camera-capturer.h
@@ -64,40 +64,27 @@ struct _GstCameraCapturer
GstCameraCapturerPrivate *priv;
};
-typedef enum
-{
- GST_CAMERA_CAPTURE_SOURCE_TYPE_NONE = 0,
- GST_CAMERA_CAPTURE_SOURCE_TYPE_DV = 1,
- GST_CAMERA_CAPTURE_SOURCE_TYPE_RAW = 2,
- GST_CAMERA_CAPTURE_SOURCE_TYPE_DSHOW = 3
-} GstCameraCaptureSourceType;
-
EXPORT GType
gst_camera_capturer_get_type (void)
- G_GNUC_CONST;
+G_GNUC_CONST;
- EXPORT void gst_camera_capturer_init_backend (int *argc, char ***argv);
- EXPORT GstCameraCapturer *gst_camera_capturer_new (gchar * filename,
- GError ** err);
- EXPORT void gst_camera_capturer_run (GstCameraCapturer * gcc);
- EXPORT void gst_camera_capturer_close (GstCameraCapturer * gcc);
- EXPORT void gst_camera_capturer_start (GstCameraCapturer * gcc);
- EXPORT void gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc);
- EXPORT void gst_camera_capturer_stop (GstCameraCapturer * gcc);
- EXPORT gboolean gst_camera_capturer_set_video_encoder (GstCameraCapturer *
- gcc, VideoEncoderType type, GError ** err);
- EXPORT gboolean gst_camera_capturer_set_audio_encoder (GstCameraCapturer *
- gcc, AudioEncoderType type, GError ** err);
- EXPORT gboolean gst_camera_capturer_set_video_muxer (GstCameraCapturer *
- gcc, VideoMuxerType type, GError ** err);
- EXPORT gboolean gst_camera_capturer_set_source (GstCameraCapturer * gcc,
- GstCameraCaptureSourceType type, GError ** err);
- EXPORT GList *gst_camera_capturer_enum_audio_devices (void);
- EXPORT GList *gst_camera_capturer_enum_video_devices (void);
- EXPORT GdkPixbuf *gst_camera_capturer_get_current_frame (GstCameraCapturer
+void gst_camera_capturer_init_backend (int *argc, char ***argv);
+GstCameraCapturer *gst_camera_capturer_new (gchar *filename, GError ** err);
+void gst_camera_capturer_run (GstCameraCapturer * gcc);
+void gst_camera_capturer_close (GstCameraCapturer * gcc);
+void gst_camera_capturer_start (GstCameraCapturer * gcc);
+void gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc);
+void gst_camera_capturer_stop (GstCameraCapturer * gcc);
+void gst_camera_capturer_set_source (GstCameraCapturer * gcc, CaptureSourceType source);
+void gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc, VideoEncoderType encoder);
+void gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc, AudioEncoderType encoder);
+void gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc, VideoMuxerType muxer);
+GList *gst_camera_capturer_enum_audio_devices (void);
+GList *gst_camera_capturer_enum_video_devices (void);
+GdkPixbuf *gst_camera_capturer_get_current_frame (GstCameraCapturer
* gcc);
- EXPORT void gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf);
- EXPORT void gst_camera_capturer_finalize (GObject * object);
+void gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf);
+void gst_camera_capturer_finalize (GObject * object);
G_END_DECLS
#endif /* _GST_CAMERA_CAPTURER_H_ */
diff --git a/libcesarplayer/gstscreenshot.c b/libcesarplayer/gstscreenshot.c
index f1df208..03f67a8 100644
--- a/libcesarplayer/gstscreenshot.c
+++ b/libcesarplayer/gstscreenshot.c
@@ -25,9 +25,8 @@
#include <string.h>
#include "gstscreenshot.h"
+#include "video-utils.h"
-GST_DEBUG_CATEGORY_EXTERN (_totem_gst_debug_cat);
-#define GST_CAT_DEFAULT _totem_gst_debug_cat
static void
feed_fakesrc (GstElement * src, GstBuffer * buf, GstPad * pad, gpointer data)
diff --git a/libcesarplayer/liblongomatch.mdp b/libcesarplayer/liblongomatch.mdp
index 1656a00..74c14e9 100644
--- a/libcesarplayer/liblongomatch.mdp
+++ b/libcesarplayer/liblongomatch.mdp
@@ -54,6 +54,7 @@
<Package file="/usr/lib/pkgconfig/gstreamer-interfaces-0.10.pc" name="GStreamer Interfaces Library" IsProject="False" />
<Package file="/usr/lib/pkgconfig/glib-2.0.pc" name="GLib" IsProject="False" />
<Package file="/usr/lib/pkgconfig/gstreamer-pbutils-0.10.pc" name="GStreamer Base Utils Library" IsProject="False" />
+ <Package file="/usr/lib/pkgconfig/gstreamer-app-0.10.pc" name="GStreamer APP" IsProject="False" />
</Packages>
<compiler ctype="GccCompiler" />
-</Project>
\ No newline at end of file
+</Project>
diff --git a/libcesarplayer/main.c b/libcesarplayer/main.c
index a2726fc..ff51aab 100644
--- a/libcesarplayer/main.c
+++ b/libcesarplayer/main.c
@@ -17,13 +17,14 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-
+/* Compile with:
+ * gcc -o test main.c gst-camera-capturer.c video-utils.c gstscreenshot.c `pkg-config --cflags --libs gstreamer-0.10 gstreamer-interfaces-0.10 gstreamer-video-0.10 gtk+-2.0` -DOSTYPE_LINUX -O0
+ */
#include <gtk/gtk.h>
-#include "gst-video-capturer.h"
#include <stdlib.h>
#include <unistd.h>
+#include "gst-camera-capturer.h"
static int i = 0;
@@ -34,22 +35,24 @@ window_state_event (GtkWidget * widget, GdkEventWindowState * event,
i++;
g_print ("%d\n", i);
if (i == 3) {
- gst_video_capturer_rec (GST_VIDEO_CAPTURER (gvc));
+ gst_camera_capturer_start (GST_CAMERA_CAPTURER (gvc));
}
if (i == 5)
- gst_video_capturer_stop (GST_VIDEO_CAPTURER (gvc));
+ gst_camera_capturer_toggle_pause (GST_CAMERA_CAPTURER (gvc));
+ if (i == 7)
+ gst_camera_capturer_toggle_pause (GST_CAMERA_CAPTURER (gvc));
+ if (i == 9)
+ gst_camera_capturer_stop (GST_CAMERA_CAPTURER (gvc));
return TRUE;
}
GtkWidget *
-create_window (GstVideoCapturer * gvc)
+create_window (GstCameraCapturer * gvc)
{
GtkWidget *window;
-
-
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Capturer");
@@ -66,19 +69,21 @@ int
main (int argc, char *argv[])
{
GtkWidget *window;
- GstVideoCapturer *gvc;
+ GstCameraCapturer *gvc;
GError *error = NULL;
gtk_init (&argc, &argv);
/*Create GstVideoCapturer */
- gst_video_capturer_init_backend (&argc, &argv);
- gvc = gst_video_capturer_new (GVC_USE_TYPE_DEVICE_CAPTURE, &error);
- //gvc = gst_video_capturer_new (GVC_USE_TYPE_VIDEO_TRANSCODE, &error );
- //g_object_set(gvc,"input_file","/home/andoni/Escritorio/RC Polo vs CD Complutense.avi",NULL);
+ gst_camera_capturer_init_backend (&argc, &argv);
+ gvc = gst_camera_capturer_new ("test", &error);
+
+ gst_camera_capturer_set_source (gvc, CAPTURE_SOURCE_TYPE_SYSTEM);
+ gst_camera_capturer_set_video_encoder (gvc, VIDEO_ENCODER_H264);
+ gst_camera_capturer_set_audio_encoder (gvc, AUDIO_ENCODER_AAC);
+ gst_camera_capturer_set_video_muxer (gvc, VIDEO_MUXER_MP4);
g_object_set (gvc, "output_file", "/home/andoni/jander.avi", NULL);
- //gvc = gst_video_capturer_new (GVC_USE_TYPE_TEST, &error );
window = create_window (gvc);
@@ -86,9 +91,7 @@ main (int argc, char *argv[])
gtk_widget_show (GTK_WIDGET (gvc));
gtk_widget_show (window);
-
-
-
+ gst_camera_capturer_run(gvc);
gtk_main ();
return 0;
diff --git a/libcesarplayer/video-utils.c b/libcesarplayer/video-utils.c
index d6fc907..a1cd54f 100644
--- a/libcesarplayer/video-utils.c
+++ b/libcesarplayer/video-utils.c
@@ -1,4 +1,31 @@
-
+/*
+ * Copyright (C) 2003-2007 the GStreamer project
+ * Julien Moutte <julien moutte net>
+ * Ronald Bultje <rbultje ronald bitfreak net>
+ * Copyright (C) 2005-2008 Tim-Philipp MÃller <tim centricular net>
+ * Copyright (C) 2009 Sebastian DrÃge <sebastian droege collabora co uk>
+ * Copyright (C) 2009 Andoni Morales Alastruey <ylatuya gmail com>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission is above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ */
#include "video-utils.h"
@@ -243,12 +270,16 @@ gst_set_window_handle(GstXOverlay *xoverlay, GdkWindow *window)
/* Retrieve window handler from GDK */
#if defined (GDK_WINDOWING_WIN32)
window_handle = (guintptr)GDK_WINDOW_HWND (window);
+ gst_x_overlay_set_window_handle (xoverlay, window_handle);
#elif defined (GDK_WINDOWING_QUARTZ)
window_handle = gdk_quartz_window_get_nsview (window);
+ gst_x_overlay_set_window_handle (xoverlay, window_handle);
#elif defined (GDK_WINDOWING_X11)
+ gdk_threads_enter ();
window_handle = GDK_WINDOW_XID (window);
-#endif
gst_x_overlay_set_window_handle (xoverlay, window_handle);
+ gdk_threads_leave ();
+#endif
}
void
diff --git a/libcesarplayer/video-utils.h b/libcesarplayer/video-utils.h
index def2d38..ee87196 100644
--- a/libcesarplayer/video-utils.h
+++ b/libcesarplayer/video-utils.h
@@ -1,3 +1,31 @@
+/*
+ * Copyright (C) 2003-2007 the GStreamer project
+ * Julien Moutte <julien moutte net>
+ * Ronald Bultje <rbultje ronald bitfreak net>
+ * Copyright (C) 2005-2008 Tim-Philipp MÃller <tim centricular net>
+ * Copyright (C) 2009 Sebastian DrÃge <sebastian droege collabora co uk>
+ * Copyright (C) 2009 Andoni Morales Alastruey <ylatuya gmail com>
+ *
+ * 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission is above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ */
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
@@ -34,7 +62,8 @@ void totem_widget_set_preferred_size (GtkWidget * widget, gint width,
gboolean totem_ratio_fits_screen (GdkWindow * window, int video_width,
int video_height, gfloat ratio);
-EXPORT void init_backend (int argc, char **argv);
-EXPORT void gst_set_window_handle (GstXOverlay *overlay, GdkWindow *window);
+void init_backend (int argc, char **argv);
+void gst_set_window_handle (GstXOverlay *overlay, GdkWindow *window);
+void init_debug();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]