[chronojump] Update libcesarplayer
- From: Andoni Morales Alastruey <amorales src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [chronojump] Update libcesarplayer
- Date: Wed, 23 Jan 2013 01:25:58 +0000 (UTC)
commit 25b00d325ac3913fd8cf6af2b313f8d5c971f4e7
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date: Wed Jan 23 02:20:14 2013 +0100
Update libcesarplayer
libcesarplayer/Makefile.am | 63 +-
.../{src => }/bacon-video-widget-gst-0.10.c | 1274 ++----------
libcesarplayer/{src => }/bacon-video-widget.h | 4 +-
.../{src => }/baconvideowidget-marshal.c | 494 +++---
.../{src => }/baconvideowidget-marshal.h | 88 +-
.../{src => }/baconvideowidget-marshal.list | 0
libcesarplayer/{src => }/common.h | 38 +
libcesarplayer/gst-camera-capturer.c | 2111 ++++++++++++++++++++
libcesarplayer/{src => }/gst-camera-capturer.h | 53 +-
libcesarplayer/gst-remuxer.c | 538 +++++
libcesarplayer/gst-remuxer.h | 72 +
libcesarplayer/{src => }/gst-smart-video-scaler.c | 0
libcesarplayer/{src => }/gst-smart-video-scaler.h | 0
libcesarplayer/{src => }/gst-video-editor.c | 45 +-
libcesarplayer/{src => }/gst-video-editor.h | 0
libcesarplayer/{src => }/gstscreenshot.c | 3 +-
libcesarplayer/{src => }/gstscreenshot.h | 0
libcesarplayer/{src => }/gstvideowidget.c | 0
libcesarplayer/{src => }/gstvideowidget.h | 0
libcesarplayer/{src => }/macros.h | 0
libcesarplayer/{src => }/main.c | 37 +-
libcesarplayer/src/Makefile.am | 55 -
libcesarplayer/src/bacon-resize.c | 338 ----
libcesarplayer/src/bacon-resize.h | 55 -
libcesarplayer/src/gst-camera-capturer.c | 1793 -----------------
libcesarplayer/src/video-utils.h | 40 -
libcesarplayer/test-editor.c | 112 +
libcesarplayer/test-remuxer.c | 71 +
libcesarplayer/{src => }/video-utils.c | 40 +-
libcesarplayer/video-utils.h | 70 +
30 files changed, 3682 insertions(+), 3712 deletions(-)
---
diff --git a/libcesarplayer/Makefile.am b/libcesarplayer/Makefile.am
index 675e822..4ab9dfd 100644
--- a/libcesarplayer/Makefile.am
+++ b/libcesarplayer/Makefile.am
@@ -1,14 +1,59 @@
## Process this file with automake to produce Makefile.in
-## Created by Anjuta
-SUBDIRS = src
+AM_CPPFLAGS = \
+ -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ $(CESARPLAYER_CFLAGS)
-# Copy all the spec files. Of cource, only one is actually used.
-dist-hook:
- for specfile in *.spec; do \
- if test -f $$specfile; then \
- cp -p $$specfile $(distdir); \
- fi \
- done
+if OSTYPE_OS_X
+AM_CPPFLAGS += \
+ -x objective-c
+endif
+
+AM_CFLAGS =\
+ -Wall\
+ -g
+
+BVWMARSHALFILES = baconvideowidget-marshal.c baconvideowidget-marshal.h
+GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
+BUILT_SOURCES = $(BVWMARSHALFILES)
+
+baconvideowidget-marshal.h: baconvideowidget-marshal.list
+ ( $(GLIB_GENMARSHAL) --prefix=baconvideowidget_marshal $(srcdir)/baconvideowidget-marshal.list --header > baconvideowidget-marshal.h )
+baconvideowidget-marshal.c: baconvideowidget-marshal.h
+ ( $(GLIB_GENMARSHAL) --prefix=baconvideowidget_marshal $(srcdir)/baconvideowidget-marshal.list --body --header > baconvideowidget-marshal.c )
+
+
+pkglib_LTLIBRARIES = \
+ libcesarplayer.la
+
+libcesarplayer_la_SOURCES = \
+ $(BVWMARSHALFILES) \
+ common.h\
+ bacon-video-widget.h\
+ bacon-video-widget-gst-0.10.c\
+ gstscreenshot.c \
+ gstscreenshot.h \
+ gst-camera-capturer.c\
+ gst-camera-capturer.h\
+ gst-remuxer.c\
+ gst-remuxer.h\
+ gst-video-editor.c\
+ gst-video-editor.h\
+ video-utils.c\
+ video-utils.h\
+ macros.h
+
+libcesarplayer_la_LDFLAGS = \
+ $(CESARPLAYER_LIBS)
+
+if OSTYPE_WINDOWS
+libcesarplayer_la_LDFLAGS += -no-undefined
+endif
+
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+ baconvideowidget-marshal.list
diff --git a/libcesarplayer/src/bacon-video-widget-gst-0.10.c b/libcesarplayer/bacon-video-widget-gst-0.10.c
similarity index 79%
rename from libcesarplayer/src/bacon-video-widget-gst-0.10.c
rename to libcesarplayer/bacon-video-widget-gst-0.10.c
index e8bbe24..5782325 100644
--- a/libcesarplayer/src/bacon-video-widget-gst-0.10.c
+++ b/libcesarplayer/bacon-video-widget-gst-0.10.c
@@ -28,9 +28,6 @@
*/
-
-
-
#include <gst/gst.h>
/* GStreamer Interfaces */
@@ -70,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>
@@ -90,7 +77,6 @@
#include "baconvideowidget-marshal.h"
#include "common.h"
#include "gstscreenshot.h"
-#include "bacon-resize.h"
#include "video-utils.h"
#define DEFAULT_HEIGHT 420
@@ -182,7 +168,9 @@ struct BaconVideoWidgetPrivate
gboolean got_redirect;
- GdkWindow *video_window;
+ GtkWidget *video_da;
+ GtkWidget *logo_da;
+ guintptr window_handle;
GdkCursor *cursor;
@@ -234,21 +222,14 @@ struct BaconVideoWidgetPrivate
GList *missing_plugins; /* GList of GstMessages */
gboolean plugin_install_in_progress;
- /* Bacon resize */
- BaconResize *bacon_resize;
};
static void bacon_video_widget_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec);
static void bacon_video_widget_get_property (GObject * object,
guint property_id, GValue * value, GParamSpec * pspec);
-static void bvw_update_interface_implementations (BaconVideoWidget * bvw);
static void bacon_video_widget_finalize (GObject * object);
-static void bvw_update_interface_implementations (BaconVideoWidget * bvw);
-static gboolean bacon_video_widget_configure_event (GtkWidget * widget,
- GdkEventConfigure * event, BaconVideoWidget * bvw);
-static void size_changed_cb (GdkScreen * screen, BaconVideoWidget * bvw);
static void bvw_process_pending_tag_messages (BaconVideoWidget * bvw);
static void bvw_stop_play_pipeline (BaconVideoWidget * bvw);
static GError *bvw_error_from_gst_error (BaconVideoWidget * bvw,
@@ -262,9 +243,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);
@@ -365,589 +343,186 @@ bvw_error_msg (BaconVideoWidget * bvw, GstMessage * msg)
}
static void
-get_media_size (BaconVideoWidget * bvw, gint * width, gint * height)
+bacon_video_widget_realize_event (GtkWidget * widget, BaconVideoWidget *bvw)
{
- if (bvw->priv->logo_mode) {
- if (bvw->priv->logo_pixbuf) {
- *width = gdk_pixbuf_get_width (bvw->priv->logo_pixbuf);
- *height = gdk_pixbuf_get_height (bvw->priv->logo_pixbuf);
- } else {
- *width = 0;
- *height = 0;
- }
- } else {
- if (bvw->priv->media_has_video) {
- GValue *disp_par = NULL;
- guint movie_par_n, movie_par_d, disp_par_n, disp_par_d, num, den;
-
- /* Create and init the fraction value */
- disp_par = g_new0 (GValue, 1);
- g_value_init (disp_par, GST_TYPE_FRACTION);
-
- /* Square pixel is our default */
- gst_value_set_fraction (disp_par, 1, 1);
-
- /* Now try getting display's pixel aspect ratio */
- if (bvw->priv->xoverlay) {
- GObjectClass *klass;
- GParamSpec *pspec;
-
- klass = G_OBJECT_GET_CLASS (bvw->priv->xoverlay);
- pspec = g_object_class_find_property (klass, "pixel-aspect-ratio");
-
- if (pspec != NULL) {
- GValue disp_par_prop = { 0, };
+ GdkWindow *window = gtk_widget_get_window (widget);
- g_value_init (&disp_par_prop, pspec->value_type);
- g_object_get_property (G_OBJECT (bvw->priv->xoverlay),
- "pixel-aspect-ratio", &disp_par_prop);
+ if (!gdk_window_ensure_native (window))
+ g_error ("Couldn't create native window needed for GstXOverlay!");
- if (!g_value_transform (&disp_par_prop, disp_par)) {
- GST_WARNING ("Transform failed, assuming pixel-aspect-ratio = 1/1");
- gst_value_set_fraction (disp_par, 1, 1);
- }
-
- g_value_unset (&disp_par_prop);
- }
- }
-
- disp_par_n = gst_value_get_fraction_numerator (disp_par);
- disp_par_d = gst_value_get_fraction_denominator (disp_par);
-
- GST_DEBUG ("display PAR is %d/%d", disp_par_n, disp_par_d);
-
- /* If movie pixel aspect ratio is enforced, use that */
- if (bvw->priv->ratio_type != BVW_RATIO_AUTO) {
- switch (bvw->priv->ratio_type) {
- case BVW_RATIO_SQUARE:
- movie_par_n = 1;
- movie_par_d = 1;
- break;
- case BVW_RATIO_FOURBYTHREE:
- movie_par_n = 4 * bvw->priv->video_height;
- movie_par_d = 3 * bvw->priv->video_width;
- break;
- case BVW_RATIO_ANAMORPHIC:
- movie_par_n = 16 * bvw->priv->video_height;
- movie_par_d = 9 * bvw->priv->video_width;
- break;
- case BVW_RATIO_DVB:
- movie_par_n = 20 * bvw->priv->video_height;
- movie_par_d = 9 * bvw->priv->video_width;
- break;
- /* handle these to avoid compiler warnings */
- case BVW_RATIO_AUTO:
- default:
- movie_par_n = 0;
- movie_par_d = 0;
- g_assert_not_reached ();
- }
- } else {
- /* Use the movie pixel aspect ratio if any */
- if (bvw->priv->movie_par) {
- movie_par_n = gst_value_get_fraction_numerator (bvw->priv->movie_par);
- movie_par_d =
- gst_value_get_fraction_denominator (bvw->priv->movie_par);
- } else {
- /* Square pixels */
- movie_par_n = 1;
- movie_par_d = 1;
- }
- }
-
- GST_DEBUG ("movie PAR is %d/%d", movie_par_n, movie_par_d);
-
- if (bvw->priv->video_width == 0 || bvw->priv->video_height == 0) {
- GST_DEBUG ("width and/or height 0, assuming 1/1 ratio");
- num = 1;
- den = 1;
- } else if (!gst_video_calculate_display_ratio (&num, &den,
- bvw->priv->video_width,
- bvw->priv->video_height,
- movie_par_n, movie_par_d, disp_par_n, disp_par_d)) {
- GST_WARNING ("overflow calculating display aspect ratio!");
- num = 1; /* FIXME: what values to use here? */
- den = 1;
- }
-
- GST_DEBUG ("calculated scaling ratio %d/%d for video %dx%d", num,
- den, bvw->priv->video_width, bvw->priv->video_height);
-
- /* now find a width x height that respects this display ratio.
- * prefer those that have one of w/h the same as the incoming video
- * using wd / hd = num / den */
-
- /* start with same height, because of interlaced video */
- /* check hd / den is an integer scale factor, and scale wd with the PAR */
- if (bvw->priv->video_height % den == 0) {
- GST_DEBUG ("keeping video height");
- bvw->priv->video_width_pixels =
- (guint) gst_util_uint64_scale (bvw->priv->video_height, num, den);
- bvw->priv->video_height_pixels = bvw->priv->video_height;
- } else if (bvw->priv->video_width % num == 0) {
- GST_DEBUG ("keeping video width");
- bvw->priv->video_width_pixels = bvw->priv->video_width;
- bvw->priv->video_height_pixels =
- (guint) gst_util_uint64_scale (bvw->priv->video_width, den, num);
- } else {
- GST_DEBUG ("approximating while keeping video height");
- bvw->priv->video_width_pixels =
- (guint) gst_util_uint64_scale (bvw->priv->video_height, num, den);
- bvw->priv->video_height_pixels = bvw->priv->video_height;
- }
- GST_DEBUG ("scaling to %dx%d", bvw->priv->video_width_pixels,
- bvw->priv->video_height_pixels);
-
- *width = bvw->priv->video_width_pixels;
- *height = bvw->priv->video_height_pixels;
-
- /* Free the PAR fraction */
- g_value_unset (disp_par);
- g_free (disp_par);
- } else {
- *width = 0;
- *height = 0;
- }
- }
-}
-
-static void
-bacon_video_widget_realize (GtkWidget * widget)
-{
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- GdkWindowAttr attributes;
- gint attributes_mask, w, h;
- GdkColor colour;
- GdkWindow *window;
- GdkEventMask event_mask;
-
- event_mask = gtk_widget_get_events (widget)
- | GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK;
- gtk_widget_set_events (widget, event_mask);
-
- GTK_WIDGET_CLASS (parent_class)->realize (widget);
-
- window = gtk_widget_get_window (widget);
-
- /* Creating our video window */
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.x = 0;
- attributes.y = 0;
- attributes.width = widget->allocation.width;
- attributes.height = widget->allocation.height;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.event_mask = gtk_widget_get_events (widget);
- attributes.event_mask |= GDK_EXPOSURE_MASK |
- GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK;
- attributes_mask = GDK_WA_X | GDK_WA_Y;
-
- bvw->priv->video_window = gdk_window_new (window,
- &attributes, attributes_mask);
- gdk_window_set_user_data (bvw->priv->video_window, widget);
- gdk_window_ensure_native(bvw->priv->video_window);
-
- gdk_color_parse ("black", &colour);
- gdk_colormap_alloc_color (gtk_widget_get_colormap (widget),
- &colour, TRUE, TRUE);
- gdk_window_set_background (window, &colour);
- gtk_widget_set_style (widget,
- gtk_style_attach (gtk_widget_get_style (widget), window));
-
- GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-
- /* Connect to configure event on the top level window */
- g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
- "configure-event", G_CALLBACK (bacon_video_widget_configure_event), bvw);
-
- /* get screen size changes */
- g_signal_connect (G_OBJECT (gtk_widget_get_screen (widget)),
- "size-changed", G_CALLBACK (size_changed_cb), bvw);
-
- /* nice hack to show the logo fullsize, while still being resizable */
- get_media_size (BACON_VIDEO_WIDGET (widget), &w, &h);
-
- /*ANDONI
- totem_widget_set_preferred_size (widget, w, h); */
-
- bvw->priv->bacon_resize = bacon_resize_new (widget);
-}
-
-static void
-bacon_video_widget_unrealize (GtkWidget * widget)
-{
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-
- g_object_unref (bvw->priv->bacon_resize);
- gdk_window_set_user_data (bvw->priv->video_window, NULL);
- gdk_window_destroy (bvw->priv->video_window);
- bvw->priv->video_window = NULL;
-
- GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
-}
-
-static void
-bacon_video_widget_show (GtkWidget * widget)
-{
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- GdkWindow *window;
-
- window = gtk_widget_get_window (widget);
- if (window)
- gdk_window_show (window);
- if (bvw->priv->video_window)
- gdk_window_show (bvw->priv->video_window);
-
- if (GTK_WIDGET_CLASS (parent_class)->show)
- GTK_WIDGET_CLASS (parent_class)->show (widget);
-}
-
-static void
-bacon_video_widget_hide (GtkWidget * widget)
-{
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- GdkWindow *window;
-
- window = gtk_widget_get_window (widget);
- if (window)
- gdk_window_hide (window);
- if (bvw->priv->video_window)
- gdk_window_hide (bvw->priv->video_window);
-
- if (GTK_WIDGET_CLASS (parent_class)->hide)
- GTK_WIDGET_CLASS (parent_class)->hide (widget);
-}
-
-static gboolean
-bacon_video_widget_configure_event (GtkWidget * widget,
- GdkEventConfigure * event, BaconVideoWidget * bvw)
-{
- GstXOverlay *xoverlay = NULL;
-
- g_return_val_if_fail (bvw != NULL, FALSE);
- g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
-
- xoverlay = bvw->priv->xoverlay;
-
- if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
- gst_x_overlay_expose (xoverlay);
- }
-
- return FALSE;
-}
-
-static void
-size_changed_cb (GdkScreen * screen, BaconVideoWidget * bvw)
-{
- /* FIXME:Used for visualization */
- //setup_vis (bvw);
+ bvw->priv->window_handle = gst_get_window_handle (window);
}
static gboolean
-bacon_video_widget_expose_event (GtkWidget * widget, GdkEventExpose * event)
+bacon_video_widget_logo_expose_event (GtkWidget * widget, GdkEventExpose * event,
+ BaconVideoWidget *bvw)
{
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- GstXOverlay *xoverlay;
gboolean draw_logo;
GdkWindow *win;
if (event && event->count > 0)
return TRUE;
+ if (event == NULL)
+ return TRUE;
+
g_mutex_lock (bvw->priv->lock);
- xoverlay = bvw->priv->xoverlay;
- if (xoverlay == NULL) {
- bvw_update_interface_implementations (bvw);
- xoverlay = bvw->priv->xoverlay;
- }
- if (xoverlay != NULL)
- gst_object_ref (xoverlay);
- g_mutex_unlock (bvw->priv->lock);
+ /* if there's only audio and no visualisation, draw the logo as well */
+ draw_logo = bvw->priv->media_has_audio && !bvw->priv->media_has_video;
+ if (!bvw->priv->logo_mode && !draw_logo)
+ goto exit;
- if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
- gst_set_window_handle(xoverlay, bvw->priv->video_window);
- }
+ win = gtk_widget_get_window (bvw->priv->logo_da);
/* Start with a nice black canvas */
- win = gtk_widget_get_window (widget);
gdk_draw_rectangle (win, gtk_widget_get_style (widget)->black_gc, TRUE, 0,
0, widget->allocation.width, widget->allocation.height);
- /* if there's only audio and no visualisation, draw the logo as well */
- draw_logo = bvw->priv->media_has_audio && !bvw->priv->media_has_video;
-
- if (bvw->priv->logo_mode || draw_logo) {
- if (bvw->priv->logo_pixbuf != NULL) {
- GdkPixbuf *frame;
- GdkPixbuf *drawing;
- guchar *pixels;
- int rowstride;
- gint width, height, alloc_width, alloc_height, logo_x, logo_y;
- gfloat ratio;
+ if (bvw->priv->logo_pixbuf != NULL) {
+ GdkPixbuf *frame;
+ GdkPixbuf *drawing;
+ guchar *pixels;
+ int rowstride;
+ gint width, height, alloc_width, alloc_height, logo_x, logo_y;
+ gfloat ratio;
- /* Checking if allocated space is smaller than our logo */
+ /* Checking if allocated space is smaller than our logo */
- width = gdk_pixbuf_get_width (bvw->priv->logo_pixbuf);
- height = gdk_pixbuf_get_height (bvw->priv->logo_pixbuf);
- alloc_width = widget->allocation.width;
- alloc_height = widget->allocation.height;
+ width = gdk_pixbuf_get_width (bvw->priv->logo_pixbuf);
+ height = gdk_pixbuf_get_height (bvw->priv->logo_pixbuf);
+ alloc_width = widget->allocation.width;
+ alloc_height = widget->allocation.height;
- if ((gfloat) alloc_width / width > (gfloat) alloc_height / height) {
- ratio = (gfloat) alloc_height / height;
- } else {
- ratio = (gfloat) alloc_width / width;
- }
-
- width *= ratio;
- height *= ratio;
+ if ((gfloat) alloc_width / width > (gfloat) alloc_height / height) {
+ ratio = (gfloat) alloc_height / height;
+ } else {
+ ratio = (gfloat) alloc_width / width;
+ }
- logo_x = (alloc_width / 2) - (width / 2);
- logo_y = (alloc_height / 2) - (height / 2);
+ width *= ratio;
+ height *= ratio;
+ logo_x = (alloc_width / 2) - (width / 2);
+ logo_y = (alloc_height / 2) - (height / 2);
- /* Drawing our frame */
- if (bvw->priv->expand_logo && !bvw->priv->drawing_mode) {
- /* Scaling to available space */
+ /* Drawing our frame */
- frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- FALSE, 8, widget->allocation.width, widget->allocation.height);
+ if (bvw->priv->expand_logo && !bvw->priv->drawing_mode) {
+ /* Scaling to available space */
- gdk_pixbuf_composite (bvw->priv->logo_pixbuf,
- frame,
- 0, 0,
- alloc_width, alloc_height,
- logo_x, logo_y, ratio, ratio, GDK_INTERP_BILINEAR, 255);
+ frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ FALSE, 8, widget->allocation.width, widget->allocation.height);
- rowstride = gdk_pixbuf_get_rowstride (frame);
+ gdk_pixbuf_composite (bvw->priv->logo_pixbuf,
+ frame,
+ 0, 0,
+ alloc_width, alloc_height,
+ logo_x, logo_y, ratio, ratio, GDK_INTERP_BILINEAR, 255);
- pixels = gdk_pixbuf_get_pixels (frame) +
- rowstride * event->area.y + event->area.x * 3;
+ rowstride = gdk_pixbuf_get_rowstride (frame);
- gdk_draw_rgb_image_dithalign (widget->window,
- widget->style->black_gc,
- event->area.x, event->area.y,
- event->area.width,
- event->area.height,
- GDK_RGB_DITHER_NORMAL, pixels,
- rowstride, event->area.x, event->area.y);
+ pixels = gdk_pixbuf_get_pixels (frame) +
+ rowstride * event->area.y + event->area.x * 3;
- g_object_unref (frame);
- } else {
- gdk_window_clear_area (win,
- 0, 0, widget->allocation.width, widget->allocation.height);
-
- if (width <= 1 || height <= 1) {
- if (xoverlay != NULL)
- gst_object_unref (xoverlay);
- gdk_window_end_paint (win);
- return TRUE;
- }
+ gdk_draw_rgb_image_dithalign (widget->window,
+ widget->style->black_gc,
+ event->area.x, event->area.y,
+ event->area.width,
+ event->area.height,
+ GDK_RGB_DITHER_NORMAL, pixels,
+ rowstride, event->area.x, event->area.y);
- frame = gdk_pixbuf_scale_simple (bvw->priv->logo_pixbuf,
- width, height, GDK_INTERP_BILINEAR);
- gdk_draw_pixbuf (win, gtk_widget_get_style (widget)->fg_gc[0],
- frame, 0, 0, logo_x, logo_y, width, height,
- GDK_RGB_DITHER_NONE, 0, 0);
-
- if (bvw->priv->drawing_mode && bvw->priv->drawing_pixbuf != NULL) {
- drawing =
- gdk_pixbuf_scale_simple (bvw->priv->drawing_pixbuf, width,
- height, GDK_INTERP_BILINEAR);
- gdk_draw_pixbuf (win,
- gtk_widget_get_style (widget)->fg_gc[0],
- drawing, 0, 0, logo_x, logo_y, width,
- height, GDK_RGB_DITHER_NONE, 0, 0);
- g_object_unref (drawing);
- }
+ g_object_unref (frame);
+ } else {
+ if (width <= 1 || height <= 1) {
+ gdk_window_end_paint (win);
+ goto exit;
+ }
- g_object_unref (frame);
+ frame = gdk_pixbuf_scale_simple (bvw->priv->logo_pixbuf,
+ width, height, GDK_INTERP_BILINEAR);
+ gdk_draw_pixbuf (win, gtk_widget_get_style (widget)->fg_gc[0],
+ frame, 0, 0, logo_x, logo_y, width, height,
+ GDK_RGB_DITHER_NONE, 0, 0);
+
+ if (bvw->priv->drawing_mode && bvw->priv->drawing_pixbuf != NULL) {
+ drawing =
+ gdk_pixbuf_scale_simple (bvw->priv->drawing_pixbuf, width,
+ height, GDK_INTERP_BILINEAR);
+ gdk_draw_pixbuf (win,
+ gtk_widget_get_style (widget)->fg_gc[0],
+ drawing, 0, 0, logo_x, logo_y, width,
+ height, GDK_RGB_DITHER_NONE, 0, 0);
+ g_object_unref (drawing);
}
- } else if (win) {
- /* No pixbuf, just draw a black background then */
- gdk_window_clear_area (win,
- 0, 0, widget->allocation.width, widget->allocation.height);
- }
- } else {
- /* no logo, pass the expose to gst */
- if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay))
- gst_x_overlay_expose (xoverlay);
- else {
- /* No xoverlay to expose yet */
- gdk_window_clear_area (win,
- 0, 0, widget->allocation.width, widget->allocation.height);
+
+ g_object_unref (frame);
}
+ } else if (win) {
+ /* No pixbuf, just draw a black background then */
+ gdk_window_clear_area (win,
+ 0, 0, widget->allocation.width, widget->allocation.height);
}
- if (xoverlay != NULL)
- gst_object_unref (xoverlay);
- return TRUE;
-}
-
-static GstNavigation *
-bvw_get_navigation_iface (BaconVideoWidget * bvw)
-{
- GstNavigation *nav = NULL;
- g_mutex_lock (bvw->priv->lock);
- if (bvw->priv->navigation == NULL)
- bvw_update_interface_implementations (bvw);
- if (bvw->priv->navigation)
- nav = gst_object_ref (GST_OBJECT (bvw->priv->navigation));
+exit:
g_mutex_unlock (bvw->priv->lock);
-
- return nav;
+ return TRUE;
}
-/* need to use gstnavigation interface for these vmethods, to allow for the sink
- to map screen coordinates to video coordinates in the presence of e.g.
- hardware scaling */
-
static gboolean
-bacon_video_widget_motion_notify (GtkWidget * widget, GdkEventMotion * event)
+bacon_video_widget_video_expose_event (GtkWidget * widget, GdkEventExpose * event,
+ BaconVideoWidget *bvw)
{
- gboolean res = FALSE;
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-
- g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
-
- if (!bvw->priv->logo_mode) {
- GstNavigation *nav = bvw_get_navigation_iface (bvw);
- if (nav) {
- gst_navigation_send_mouse_event (nav, "mouse-move", 0, event->x,
- event->y);
- gst_object_unref (GST_OBJECT (nav));
- }
- }
-
- if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
- res |= GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
-
- return res;
-}
+ GstXOverlay *xoverlay;
+ GdkWindow *win;
-static gboolean
-bacon_video_widget_button_press (GtkWidget * widget, GdkEventButton * event)
-{
- gboolean res = FALSE;
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
+ if (event && event->count > 0)
+ return TRUE;
- g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
+ if (event == NULL)
+ return TRUE;
- if (!bvw->priv->logo_mode) {
- GstNavigation *nav = bvw_get_navigation_iface (bvw);
- if (nav) {
- gst_navigation_send_mouse_event (nav,
- "mouse-button-press", event->button, event->x, event->y);
- gst_object_unref (GST_OBJECT (nav));
+ g_mutex_lock (bvw->priv->lock);
- /* FIXME need to check whether the backend will have handled
- * the button press
- res = TRUE; */
- }
+ xoverlay = bvw->priv->xoverlay;
+ if (xoverlay != NULL) {
+ gst_object_ref (xoverlay);
+ gst_set_window_handle (xoverlay, bvw->priv->window_handle);
}
- if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
- res |= GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
-
- return res;
-}
-
-static gboolean
-bacon_video_widget_button_release (GtkWidget * widget, GdkEventButton * event)
-{
- gboolean res = FALSE;
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-
- g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
-
- if (!bvw->priv->logo_mode) {
- GstNavigation *nav = bvw_get_navigation_iface (bvw);
- if (nav) {
- gst_navigation_send_mouse_event (nav,
- "mouse-button-release", event->button, event->x, event->y);
- gst_object_unref (GST_OBJECT (nav));
-
- res = TRUE;
- }
+ if (bvw->priv->logo_mode) {
+#if !defined (GDK_WINDOWING_QUARTZ)
+ g_mutex_unlock (bvw->priv->lock);
+ bacon_video_widget_logo_expose_event (widget, event, bvw);
+ g_mutex_lock (bvw->priv->lock);
+#endif
+ goto exit;
}
- if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
- res |=
- GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
-
- return res;
-}
-
-static void
-bacon_video_widget_size_request (GtkWidget * widget,
- GtkRequisition * requisition)
-{
- requisition->width = 240;
- requisition->height = 180;
-}
-
-static void
-resize_video_window (BaconVideoWidget * bvw)
-{
- const GtkAllocation *allocation;
- gfloat width, height, ratio, x, y;
- int w, h;
-
- g_return_if_fail (bvw != NULL);
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
- allocation = >K_WIDGET (bvw)->allocation;
-
- get_media_size (bvw, &w, &h);
- if (!w || !h) {
- w = allocation->width;
- h = allocation->height;
+ /* no logo, pass the expose to gst */
+ if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)){
+ gst_x_overlay_expose (xoverlay);
}
- width = w;
- height = h;
-
- /* calculate ratio for fitting video into the available space */
- if ((gfloat) allocation->width / width > (gfloat) allocation->height / height) {
- ratio = (gfloat) allocation->height / height;
- } else {
- ratio = (gfloat) allocation->width / width;
+ else {
+ /* No xoverlay to expose yet */
+ win = gtk_widget_get_window (bvw->priv->video_da);
+ gdk_window_clear_area (win,
+ 0, 0, widget->allocation.width, widget->allocation.height);
}
- /* apply zoom factor */
- ratio = ratio * bvw->priv->zoom;
-
- width *= ratio;
- height *= ratio;
- x = (allocation->width - width) / 2;
- y = (allocation->height - height) / 2;
-
- gdk_window_move_resize (bvw->priv->video_window, x, y, width, height);
- gtk_widget_queue_draw (GTK_WIDGET (bvw));
-}
-
-static void
-bacon_video_widget_size_allocate (GtkWidget * widget,
- GtkAllocation * allocation)
-{
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (widget));
+exit:
- widget->allocation = *allocation;
-
- if (GTK_WIDGET_REALIZED (widget)) {
-
- gdk_window_move_resize (gtk_widget_get_window (widget),
- allocation->x, allocation->y, allocation->width, allocation->height);
+ if (xoverlay != NULL)
+ gst_object_unref (xoverlay);
- resize_video_window (bvw);
- }
+ g_mutex_unlock (bvw->priv->lock);
+ return TRUE;
}
-
static gboolean
bvw_boolean_handled_accumulator (GSignalInvocationHint * ihint,
GValue * return_accu, const GValue * handler_return, gpointer foobar)
@@ -966,28 +541,13 @@ static void
bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
{
GObjectClass *object_class;
- GtkWidgetClass *widget_class;
object_class = (GObjectClass *) klass;
- widget_class = (GtkWidgetClass *) klass;
parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (object_class, sizeof (BaconVideoWidgetPrivate));
- /* GtkWidget */
- widget_class->size_request = bacon_video_widget_size_request;
- widget_class->size_allocate = bacon_video_widget_size_allocate;
- widget_class->realize = bacon_video_widget_realize;
- widget_class->unrealize = bacon_video_widget_unrealize;
- widget_class->show = bacon_video_widget_show;
- widget_class->hide = bacon_video_widget_hide;
- widget_class->expose_event = bacon_video_widget_expose_event;
- widget_class->motion_notify_event = bacon_video_widget_motion_notify;
- widget_class->button_press_event = bacon_video_widget_button_press;
- widget_class->button_release_event = bacon_video_widget_button_release;
-
-
/* GObject */
object_class->set_property = bacon_video_widget_set_property;
object_class->get_property = bacon_video_widget_get_property;
@@ -1129,7 +689,6 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
BaconVideoWidgetPrivate *priv;
GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
bvw->priv = priv =
G_TYPE_INSTANCE_GET_PRIVATE (bvw, BACON_TYPE_VIDEO_WIDGET,
@@ -1144,16 +703,34 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
bvw->priv->missing_plugins = NULL;
bvw->priv->plugin_install_in_progress = FALSE;
-}
-static void
-shrink_toplevel (BaconVideoWidget * bvw)
-{
- GtkWidget *toplevel, *widget;
- widget = GTK_WIDGET (bvw);
- toplevel = gtk_widget_get_toplevel (widget);
- if (toplevel != widget && GTK_IS_WINDOW (toplevel) != FALSE)
- gtk_window_resize (GTK_WINDOW (toplevel), 1, 1);
+ bvw->priv->video_da = gtk_drawing_area_new ();
+ gtk_box_pack_start (GTK_BOX (bvw), bvw->priv->video_da, TRUE, TRUE, 0);
+ gtk_widget_show (bvw->priv->video_da);
+ GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw->priv->video_da), GTK_DOUBLE_BUFFERED);
+
+#if defined (GDK_WINDOWING_QUARTZ)
+ bvw->priv->logo_da = gtk_drawing_area_new ();
+ gtk_box_pack_start (GTK_BOX (bvw), bvw->priv->logo_da, TRUE, TRUE, 0);
+ gtk_widget_show (bvw->priv->logo_da);
+
+ g_signal_connect (GTK_WIDGET (bvw->priv->logo_da), "expose-event",
+ G_CALLBACK (bacon_video_widget_logo_expose_event), bvw);
+#else
+ bvw->priv->logo_da = bvw->priv->video_da;
+#endif
+
+ gtk_widget_add_events (GTK_WIDGET (bvw->priv->video_da),
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
+
+ g_signal_connect (GTK_WIDGET (bvw->priv->video_da), "realize",
+ G_CALLBACK (bacon_video_widget_realize_event), bvw);
+
+ g_signal_connect (GTK_WIDGET (bvw->priv->video_da), "expose-event",
+ G_CALLBACK (bacon_video_widget_video_expose_event), bvw);
+
+ bacon_video_widget_set_logo_mode (bvw, TRUE);
}
static gboolean bvw_query_timeout (BaconVideoWidget * bvw);
@@ -1177,7 +754,6 @@ static void
bvw_handle_application_message (BaconVideoWidget * bvw, GstMessage * msg)
{
const gchar *msg_name;
- GdkWindow *window;
msg_name = gst_structure_get_name (msg->structure);
g_return_if_fail (msg_name != NULL);
@@ -1186,35 +762,8 @@ bvw_handle_application_message (BaconVideoWidget * bvw, GstMessage * msg)
if (strcmp (msg_name, "stream-changed") == 0) {
bvw_update_stream_info (bvw);
- } else if (strcmp (msg_name, "video-size") == 0) {
- /* if we're not interactive, we want to announce metadata
- * only later when we can be sure we got it all */
- if (bvw->priv->use_type == BVW_USE_TYPE_VIDEO ||
- bvw->priv->use_type == BVW_USE_TYPE_AUDIO) {
- g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0, NULL);
- }
-
- if (bvw->priv->auto_resize
- && !bvw->priv->fullscreen_mode && !bvw->priv->window_resized) {
- bacon_video_widget_set_scale_ratio (bvw, 1);
- } else {
- bacon_video_widget_size_allocate (GTK_WIDGET (bvw),
- >K_WIDGET (bvw)->allocation);
-
- /* Uhm, so this ugly hack here makes media loading work for
- * weird laptops with NVIDIA graphics cards... Dunno what the
- * bug is really, but hey, it works. :). */
- window = gtk_widget_get_window (GTK_WIDGET (bvw));
- if (window) {
- gdk_window_hide (window);
- gdk_window_show (window);
-
- bacon_video_widget_expose_event (GTK_WIDGET (bvw), NULL);
- }
- }
- bvw->priv->window_resized = TRUE;
} else {
- g_message ("Unhandled application message %s", msg_name);
+ GST_DEBUG ("Unhandled application message %s", msg_name);
}
}
@@ -1607,7 +1156,6 @@ bvw_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
g_signal_emit (bvw, bvw_signals[SIGNAL_STATE_CHANGE], 0, TRUE);
}
-
if (old_state == GST_STATE_READY && new_state == GST_STATE_PAUSED) {
GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN_CAST (bvw->priv->play),
GST_DEBUG_GRAPH_SHOW_ALL ^
@@ -1616,7 +1164,6 @@ bvw_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
if (bacon_video_widget_get_stream_length (bvw) == 0) {
GST_DEBUG ("Failed to query duration in PAUSED state?!");
}
- break;
bvw_update_stream_info (bvw);
if (!bvw_check_missing_plugins_on_preroll (bvw)) {
/* show a non-fatal warning message if we can't decode the video */
@@ -1849,9 +1396,6 @@ parse_stream_info (BaconVideoWidget * bvw)
gint i;
bvw->priv->media_has_video = TRUE;
- if (bvw->priv->video_window)
- gdk_window_show (bvw->priv->video_window);
-
for (i = 0; i < n_video && videopad == NULL; i++)
g_signal_emit_by_name (bvw->priv->play, "get-video-pad", i, &videopad);
}
@@ -1859,16 +1403,16 @@ parse_stream_info (BaconVideoWidget * bvw)
bvw->priv->media_has_audio = FALSE;
if (n_audio > 0) {
bvw->priv->media_has_audio = TRUE;
- if (!bvw->priv->media_has_video && bvw->priv->video_window) {
- gint flags;
+ if (!bvw->priv->media_has_video) {
+ /*gint flags;*/
- g_object_get (bvw->priv->play, "flags", &flags, NULL);
+ /*g_object_get (bvw->priv->play, "flags", &flags, NULL);*/
- gdk_window_hide (bvw->priv->video_window);
- GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
- flags &= ~GST_PLAY_FLAGS_VIS;
+ /*gdk_window_hide (bvw->priv->video_window);*/
+ /*GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);*/
+ /*flags &= ~GST_PLAY_FLAGS_VIS;*/
- g_object_set (bvw->priv->play, "flags", flags, NULL);
+ /*g_object_set (bvw->priv->play, "flags", flags, NULL);*/
}
}
@@ -1925,10 +1469,6 @@ bacon_video_widget_finalize (GObject * object)
g_free (bvw->priv->mrl);
bvw->priv->mrl = NULL;
-
-
-
-
if (bvw->priv->play != NULL && GST_IS_ELEMENT (bvw->priv->play)) {
gst_element_set_state (bvw->priv->play, GST_STATE_NULL);
gst_object_unref (bvw->priv->play);
@@ -3223,16 +2763,6 @@ bacon_video_widget_segment_seek (BaconVideoWidget * bvw, gint64 start,
GST_LOG ("Segment seeking from %" GST_TIME_FORMAT,
GST_TIME_ARGS (start * GST_MSECOND));
-
- if (start > bvw->priv->stream_length
- && bvw->priv->stream_length > 0
- && !g_str_has_prefix (bvw->priv->mrl, "dvd:")
- && !g_str_has_prefix (bvw->priv->mrl, "vcd:")) {
- if (bvw->priv->eos_id == 0)
- bvw->priv->eos_id = g_idle_add (bvw_signal_eos_delayed, bvw);
- return TRUE;
- }
-
got_time_tick (bvw->priv->play, start * GST_MSECOND, bvw);
gst_element_seek (bvw->priv->play, rate,
GST_FORMAT_TIME,
@@ -3280,7 +2810,7 @@ bacon_video_widget_seek_to_previous_frame (BaconVideoWidget * bvw,
g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE);
- //Round framerate to the nearest integer
+ //Round framerate to the nearest integer
fps = (bvw->priv->video_fps_n + bvw->priv->video_fps_d / 2) /
bvw->priv->video_fps_d;
pos = bacon_video_widget_get_accurate_current_time (bvw);
@@ -3622,24 +3152,36 @@ bacon_video_widget_set_logo_mode (BaconVideoWidget * bvw, gboolean logo_mode)
logo_mode = logo_mode != FALSE;
+ g_mutex_lock (bvw->priv->lock);
+
if (priv->logo_mode != logo_mode) {
priv->logo_mode = logo_mode;
- if (priv->video_window) {
- if (logo_mode) {
- gdk_window_hide (priv->video_window);
- GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
- } else {
- gdk_window_show (priv->video_window);
- GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
- }
+ if (logo_mode) {
+#if defined (GDK_WINDOWING_QUARTZ)
+ gtk_widget_show (priv->logo_da);
+ gtk_widget_hide (priv->video_da);
+#else
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw->priv->video_da), GTK_DOUBLE_BUFFERED);
+#endif
+ } else {
+#if defined (GDK_WINDOWING_QUARTZ)
+ gtk_widget_show (priv->video_da);
+ gtk_widget_hide (priv->logo_da);
+#else
+ GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw->priv->video_da), GTK_DOUBLE_BUFFERED);
+#endif
}
+ g_mutex_unlock (bvw->priv->lock);
+
g_object_notify (G_OBJECT (bvw), "logo_mode");
g_object_notify (G_OBJECT (bvw), "seekable");
/* Queue a redraw of the widget */
gtk_widget_queue_draw (GTK_WIDGET (bvw));
+ } else {
+ g_mutex_unlock (bvw->priv->lock);
}
}
@@ -3833,29 +3375,29 @@ bacon_video_widget_get_volume (BaconVideoWidget * bvw)
*
* Fullscreen rendering is done only when possible, as xvidmode is required.
**/
-void
-bacon_video_widget_set_fullscreen (BaconVideoWidget * bvw, gboolean fullscreen)
-{
- gboolean have_xvidmode;
+/*void*/
+/*bacon_video_widget_set_fullscreen (BaconVideoWidget * bvw, gboolean fullscreen)*/
+/*{*/
+ /*gboolean have_xvidmode;*/
- g_return_if_fail (bvw != NULL);
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
+ /*g_return_if_fail (bvw != NULL);*/
+ /*g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));*/
- g_object_get (G_OBJECT (bvw->priv->bacon_resize),
- "have-xvidmode", &have_xvidmode, NULL);
+ /*g_object_get (G_OBJECT (bvw->priv->bacon_resize),*/
+ /*"have-xvidmode", &have_xvidmode, NULL);*/
- if (have_xvidmode == FALSE)
- return;
+ /*if (have_xvidmode == FALSE)*/
+ /*return;*/
- bvw->priv->fullscreen_mode = fullscreen;
+ /*bvw->priv->fullscreen_mode = fullscreen;*/
- if (fullscreen == FALSE) {
- bacon_resize_restore (bvw->priv->bacon_resize);
- /* Turn fullscreen on when we have xvidmode */
- } else if (have_xvidmode != FALSE) {
- bacon_resize_resize (bvw->priv->bacon_resize);
- }
-}
+ /*if (fullscreen == FALSE) {*/
+ /*bacon_resize_restore (bvw->priv->bacon_resize);*/
+ /*[> Turn fullscreen on when we have xvidmode <]*/
+ /*} else if (have_xvidmode != FALSE) {*/
+ /*bacon_resize_resize (bvw->priv->bacon_resize);*/
+ /*}*/
+/*}*/
/**
@@ -3984,225 +3526,6 @@ bacon_video_widget_get_aspect_ratio (BaconVideoWidget * bvw)
}
/**
- * bacon_video_widget_set_scale_ratio:
- * @bvw: a #BaconVideoWidget
- * @ratio: the new scale ratio
- *
- * Sets the ratio by which the widget will scale videos when they are
- * displayed. If @ratio is set to %0, the highest ratio possible will
- * be chosen.
- **/
-void
-bacon_video_widget_set_scale_ratio (BaconVideoWidget * bvw, gfloat ratio)
-{
- gint w, h;
-
- g_return_if_fail (bvw != NULL);
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
- g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play));
-
- GST_DEBUG ("ratio = %.2f", ratio);
-
- if (bvw->priv->video_window == NULL)
- return;
-
- get_media_size (bvw, &w, &h);
-
-
- if (ratio == 0.0) {
- if (totem_ratio_fits_screen (bvw->priv->video_window, w, h, 2.0))
- ratio = 2.0;
- else if (totem_ratio_fits_screen (bvw->priv->video_window, w, h, 1.0))
- ratio = 1.0;
- else if (totem_ratio_fits_screen (bvw->priv->video_window, w, h, 0.5))
- ratio = 0.5;
- else
- return;
- } else {
- if (!totem_ratio_fits_screen (bvw->priv->video_window, w, h, ratio)) {
- GST_DEBUG ("movie doesn't fit on screen @ %.1fx (%dx%d)", w, h, ratio);
- return;
- }
- }
- w = (gfloat) w *ratio;
- h = (gfloat) h *ratio;
-
- shrink_toplevel (bvw);
-
- GST_DEBUG ("setting preferred size %dx%d", w, h);
- totem_widget_set_preferred_size (GTK_WIDGET (bvw), w, h);
-}
-
-/**
- * bacon_video_widget_set_zoom:
- * @bvw: a #BaconVideoWidget
- * @zoom: a percentage zoom factor
- *
- * Sets the zoom factor applied to the video when it is displayed,
- * as an integeric percentage between %0 and %1
- * (e.g. set @zoom to %1 to not zoom at all).
- **/
-void
-bacon_video_widget_set_zoom (BaconVideoWidget * bvw, double zoom)
-{
- g_return_if_fail (bvw != NULL);
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
- bvw->priv->zoom = zoom;
- if (bvw->priv->video_window != NULL)
- resize_video_window (bvw);
-}
-
-/**
- * bacon_video_widget_get_zoom:
- * @bvw: a #BaconVideoWidget
- *
- * Returns the zoom factor applied to videos displayed by the widget,
- * as an integeric percentage between %0 and %1
- * (e.g. %1 means no zooming at all).
- *
- * Return value: the zoom factor
- **/
-double
-bacon_video_widget_get_zoom (BaconVideoWidget * bvw)
-{
- g_return_val_if_fail (bvw != NULL, 1.0);
- g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
-
- return bvw->priv->zoom;
-}
-
-
-/* Search for the color balance channel corresponding to type and return it. */
-static GstColorBalanceChannel *
-bvw_get_color_balance_channel (GstColorBalance * color_balance,
- BvwVideoProperty type)
-{
- const GList *channels;
-
- channels = gst_color_balance_list_channels (color_balance);
-
- for (; channels != NULL; channels = channels->next) {
- GstColorBalanceChannel *c = channels->data;
-
- if (type == BVW_VIDEO_BRIGHTNESS && g_strrstr (c->label, "BRIGHTNESS"))
- return g_object_ref (c);
- else if (type == BVW_VIDEO_CONTRAST && g_strrstr (c->label, "CONTRAST"))
- return g_object_ref (c);
- else if (type == BVW_VIDEO_SATURATION && g_strrstr (c->label, "SATURATION"))
- return g_object_ref (c);
- else if (type == BVW_VIDEO_HUE && g_strrstr (c->label, "HUE"))
- return g_object_ref (c);
- }
-
- return NULL;
-}
-
-/**
- * bacon_video_widget_get_video_property:
- * @bvw: a #BaconVideoWidget
- * @type: the type of property
- *
- * Returns the given property of the video, such as its brightness or saturation.
- *
- * It is returned as a percentage in the full range of integer values; from %0
- * to %G_MAXINT, where %G_MAXINT/2 is the default.
- *
- * Return value: the property's value, in the range %0 to %G_MAXINT
- **/
-int
-bacon_video_widget_get_video_property (BaconVideoWidget * bvw,
- BvwVideoProperty type)
-{
- int ret;
-
- g_return_val_if_fail (bvw != NULL, 65535 / 2);
- g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 65535 / 2);
-
- g_mutex_lock (bvw->priv->lock);
-
- ret = 0;
-
- if (bvw->priv->balance && GST_IS_COLOR_BALANCE (bvw->priv->balance)) {
- GstColorBalanceChannel *found_channel = NULL;
-
- found_channel = bvw_get_color_balance_channel (bvw->priv->balance, type);
-
- if (found_channel && GST_IS_COLOR_BALANCE_CHANNEL (found_channel)) {
- gint cur;
-
- cur = gst_color_balance_get_value (bvw->priv->balance, found_channel);
-
- GST_DEBUG ("channel %s: cur=%d, min=%d, max=%d",
- found_channel->label, cur, found_channel->min_value,
- found_channel->max_value);
-
- ret = floor (0.5 +
- ((double) cur - found_channel->min_value) * 65535 /
- ((double) found_channel->max_value - found_channel->min_value));
-
- GST_DEBUG ("channel %s: returning value %d", found_channel->label, ret);
- g_object_unref (found_channel);
- goto done;
- } else {
- ret = -1;
- }
- }
-
-done:
-
- g_mutex_unlock (bvw->priv->lock);
- return ret;
-}
-
-/**
- * bacon_video_widget_set_video_property:
- * @bvw: a #BaconVideoWidget
- * @type: the type of property
- * @value: the property's value, in the range %0 to %G_MAXINT
- *
- * Sets the given property of the video, such as its brightness or saturation.
- *
- * It should be given as a percentage in the full range of integer values; from %0
- * to %G_MAXINT, where %G_MAXINT/2 is the default.
- **/
-void
-bacon_video_widget_set_video_property (BaconVideoWidget * bvw,
- BvwVideoProperty type, int value)
-{
- g_return_if_fail (bvw != NULL);
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
- GST_DEBUG ("set video property type %d to value %d", type, value);
-
- if (!(value <= 65535 && value >= 0))
- return;
-
- if (bvw->priv->balance && GST_IS_COLOR_BALANCE (bvw->priv->balance)) {
- GstColorBalanceChannel *found_channel = NULL;
-
- found_channel = bvw_get_color_balance_channel (bvw->priv->balance, type);
-
- if (found_channel && GST_IS_COLOR_BALANCE_CHANNEL (found_channel)) {
- int i_value;
-
- i_value = floor (0.5 + value * ((double) found_channel->max_value -
- found_channel->min_value) / 65535 + found_channel->min_value);
-
- GST_DEBUG ("channel %s: set to %d/65535", found_channel->label, value);
-
- gst_color_balance_set_value (bvw->priv->balance, found_channel, i_value);
-
- GST_DEBUG ("channel %s: val=%d, min=%d, max=%d",
- found_channel->label, i_value, found_channel->min_value,
- found_channel->max_value);
-
- g_object_unref (found_channel);
- }
- }
-}
-
-/**
* bacon_video_widget_get_position:
* @bvw: a #BaconVideoWidget
*
@@ -5138,7 +4461,7 @@ bacon_video_widget_get_current_frame (BaconVideoWidget * bvw)
/* */
/* =========================================== */
-G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_TYPE_EVENT_BOX)
+G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_TYPE_HBOX)
/* applications must use exactly one of bacon_video_widget_get_option_group()
* OR bacon_video_widget_init_backend(), but not both */
/**
@@ -5185,151 +4508,6 @@ bacon_video_widget_error_quark (void)
return q;
}
-/* fold function to pick the best colorspace element */
-static gboolean
-find_colorbalance_element (GstElement * element, GValue * ret, GstElement ** cb)
-{
- GstColorBalanceClass *cb_class;
-
- GST_DEBUG ("Checking element %s ...", GST_OBJECT_NAME (element));
-
- if (!GST_IS_COLOR_BALANCE (element))
- return TRUE;
-
- GST_DEBUG ("Element %s is a color balance", GST_OBJECT_NAME (element));
-
- cb_class = GST_COLOR_BALANCE_GET_CLASS (element);
- if (GST_COLOR_BALANCE_TYPE (cb_class) == GST_COLOR_BALANCE_HARDWARE) {
- gst_object_replace ((GstObject **) cb, (GstObject *) element);
- /* shortcuts the fold */
- return FALSE;
- } else if (*cb == NULL) {
- gst_object_replace ((GstObject **) cb, (GstObject *) element);
- return TRUE;
- } else {
- return TRUE;
- }
-}
-
-static gboolean
-bvw_update_interfaces_delayed (BaconVideoWidget * bvw)
-{
- GST_DEBUG ("Delayed updating interface implementations");
- g_mutex_lock (bvw->priv->lock);
- bvw_update_interface_implementations (bvw);
- bvw->priv->interface_update_id = 0;
- g_mutex_unlock (bvw->priv->lock);
-
- return FALSE;
-}
-
-/* Must be called with bvw->priv->lock held */
-static void
-bvw_update_interface_implementations (BaconVideoWidget * bvw)
-{
- GstColorBalance *old_balance = bvw->priv->balance;
- GstXOverlay *old_xoverlay = bvw->priv->xoverlay;
- GstElement *video_sink = NULL;
- GstElement *element = NULL;
- GstIterator *iter;
-
- if (g_thread_self () != gui_thread) {
- if (bvw->priv->balance)
- gst_object_unref (bvw->priv->balance);
- bvw->priv->balance = NULL;
- if (bvw->priv->xoverlay)
- gst_object_unref (bvw->priv->xoverlay);
- bvw->priv->xoverlay = NULL;
- if (bvw->priv->navigation)
- gst_object_unref (bvw->priv->navigation);
- bvw->priv->navigation = NULL;
-
- if (bvw->priv->interface_update_id)
- g_source_remove (bvw->priv->interface_update_id);
- bvw->priv->interface_update_id =
- g_idle_add ((GSourceFunc) bvw_update_interfaces_delayed, bvw);
- return;
- }
-
- g_object_get (bvw->priv->play, "video-sink", &video_sink, NULL);
- g_assert (video_sink != NULL);
-
- /* We try to get an element supporting XOverlay interface */
- if (GST_IS_BIN (video_sink)) {
- GST_DEBUG ("Retrieving xoverlay from bin ...");
- element = gst_bin_get_by_interface (GST_BIN (video_sink),
- GST_TYPE_X_OVERLAY);
- } else {
- element = gst_object_ref (video_sink);
- }
-
- if (GST_IS_X_OVERLAY (element)) {
- GST_DEBUG ("Found xoverlay: %s", GST_OBJECT_NAME (element));
- bvw->priv->xoverlay = GST_X_OVERLAY (element);
- } else {
- GST_DEBUG ("No xoverlay found");
- if (element)
- gst_object_unref (element);
- bvw->priv->xoverlay = NULL;
- }
-
- /* Try to find the navigation interface */
- if (GST_IS_BIN (video_sink)) {
- GST_DEBUG ("Retrieving navigation from bin ...");
- element = gst_bin_get_by_interface (GST_BIN (video_sink),
- GST_TYPE_NAVIGATION);
- } else {
- element = gst_object_ref (video_sink);
- }
-
- if (GST_IS_NAVIGATION (element)) {
- GST_DEBUG ("Found navigation: %s", GST_OBJECT_NAME (element));
- bvw->priv->navigation = GST_NAVIGATION (element);
- } else {
- GST_DEBUG ("No navigation found");
- if (element)
- gst_object_unref (element);
- bvw->priv->navigation = NULL;
- }
-
- /* Find best color balance element (using custom iterator so
- * we can prefer hardware implementations to software ones) */
-
- /* FIXME: this doesn't work reliably yet, most of the time
- * the fold function doesn't even get called, while sometimes
- * it does ... */
- iter = gst_bin_iterate_all_by_interface (GST_BIN (bvw->priv->play),
- GST_TYPE_COLOR_BALANCE);
- /* naively assume no resync */
- element = NULL;
- gst_iterator_fold (iter, (GstIteratorFoldFunction)
- find_colorbalance_element, NULL, &element);
- gst_iterator_free (iter);
-
- if (element) {
- bvw->priv->balance = GST_COLOR_BALANCE (element);
- GST_DEBUG ("Best colorbalance found: %s",
- GST_OBJECT_NAME (bvw->priv->balance));
- } else if (GST_IS_COLOR_BALANCE (bvw->priv->xoverlay)) {
- bvw->priv->balance = GST_COLOR_BALANCE (bvw->priv->xoverlay);
- gst_object_ref (bvw->priv->balance);
- GST_DEBUG ("Colorbalance backup found: %s",
- GST_OBJECT_NAME (bvw->priv->balance));
- } else {
- GST_DEBUG ("No colorbalance found");
- bvw->priv->balance = NULL;
- }
-
- if (old_xoverlay)
- gst_object_unref (GST_OBJECT (old_xoverlay));
-
- if (old_balance)
- gst_object_unref (GST_OBJECT (old_balance));
-
- gst_object_unref (video_sink);
-}
-
-
static void
bvw_element_msg_sync (GstBus * bus, GstMessage * msg, gpointer data)
{
@@ -5344,38 +4522,28 @@ bvw_element_msg_sync (GstBus * bus, GstMessage * msg, gpointer data)
/* This only gets sent if we haven't set an ID yet. This is our last
* chance to set it before the video sink will create its own window */
if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) {
+ GstObject *sender = GST_MESSAGE_SRC (msg);
+
GST_INFO ("Handling sync prepare-xwindow-id message");
g_mutex_lock (bvw->priv->lock);
- bvw_update_interface_implementations (bvw);
- g_mutex_unlock (bvw->priv->lock);
-
- if (bvw->priv->xoverlay == NULL) {
- GstObject *sender = GST_MESSAGE_SRC (msg);
- if (sender && GST_IS_X_OVERLAY (sender))
- bvw->priv->xoverlay = GST_X_OVERLAY (gst_object_ref (sender));
+
+ if (bvw->priv->xoverlay != NULL) {
+ gst_object_unref (bvw->priv->xoverlay);
}
- g_return_if_fail (bvw->priv->xoverlay != NULL);
- g_return_if_fail (bvw->priv->video_window != NULL);
+ if (sender && GST_IS_X_OVERLAY (sender))
+ bvw->priv->xoverlay = GST_X_OVERLAY (gst_object_ref (sender));
- gst_set_window_handle(bvw->priv->xoverlay, bvw->priv->video_window);
+ g_return_if_fail (bvw->priv->xoverlay != NULL);
+ g_return_if_fail (bvw->priv->window_handle != 0);
+ g_object_set (GST_ELEMENT (bvw->priv->xoverlay), "force-aspect-ratio", TRUE, NULL);
+ gst_set_window_handle(bvw->priv->xoverlay, bvw->priv->window_handle);
+ g_mutex_unlock (bvw->priv->lock);
}
}
-static void
-got_new_video_sink_bin_element (GstBin * video_sink, GstElement * element,
- gpointer data)
-{
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (data);
-
- g_mutex_lock (bvw->priv->lock);
- bvw_update_interface_implementations (bvw);
- g_mutex_unlock (bvw->priv->lock);
-
-}
-
/**
* bacon_video_widget_new:
* @width: initial or expected video width, in pixels, or %-1
@@ -5404,13 +4572,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);
@@ -5419,6 +4580,11 @@ bacon_video_widget_new (int width, int height, BvwUseType type, GError ** err)
bvw = g_object_new (bacon_video_widget_get_type (), NULL);
+ /* show the gui. */
+ gtk_widget_show_all (GTK_WIDGET(bvw));
+
+ bacon_video_widget_set_logo_mode (bvw, TRUE);
+
bvw->priv->use_type = type;
GST_INFO ("use_type = %d", type);
@@ -5435,7 +4601,6 @@ bacon_video_widget_new (int width, int height, BvwUseType type, GError ** err)
}
bvw->priv->bus = gst_element_get_bus (bvw->priv->play);
-
gst_bus_add_signal_watch (bvw->priv->bus);
bvw->priv->sig_bus_async =
@@ -5622,7 +4787,7 @@ bacon_video_widget_new (int width, int height, BvwUseType type, GError ** err)
if (type == BVW_USE_TYPE_VIDEO) {
GstStateChangeReturn ret;
- /* wait for video sink to finish changing to READY state,
+ /* wait for video sink to finish changing to READY state,
* otherwise we won't be able to detect the colorbalance interface */
ret = gst_element_get_state (video_sink, NULL, NULL, 5 * GST_SECOND);
@@ -5634,7 +4799,6 @@ bacon_video_widget_new (int width, int height, BvwUseType type, GError ** err)
"Please select another video output in the Multimedia Systems Selector."));
return NULL;
}
- bvw_update_interface_implementations (bvw);
}
@@ -5645,16 +4809,6 @@ bacon_video_widget_new (int width, int height, BvwUseType type, GError ** err)
g_signal_connect (bvw->priv->bus, "sync-message::element",
G_CALLBACK (bvw_element_msg_sync), bvw);
- if (GST_IS_BIN (video_sink)) {
- /* video sink bins like gsettingsvideosink might remove their children and
- * create new ones when set to NULL state, and they are currently set
- * to NULL state whenever playbin re-creates its internal video bin
- * (it sets all elements to NULL state before gst_bin_remove()ing them) */
- g_signal_connect (video_sink, "element-added",
- G_CALLBACK (got_new_video_sink_bin_element), bvw);
- }
-
-
return GTK_WIDGET (bvw);
/* errors */
diff --git a/libcesarplayer/src/bacon-video-widget.h b/libcesarplayer/bacon-video-widget.h
similarity index 99%
rename from libcesarplayer/src/bacon-video-widget.h
rename to libcesarplayer/bacon-video-widget.h
index d2e5746..5a2753d 100644
--- a/libcesarplayer/src/bacon-video-widget.h
+++ b/libcesarplayer/bacon-video-widget.h
@@ -52,13 +52,13 @@ typedef struct BaconVideoWidgetPrivate BaconVideoWidgetPrivate;
typedef struct
{
- GtkEventBox parent;
+ GtkHBox parent;
BaconVideoWidgetPrivate *priv;
} BaconVideoWidget;
typedef struct
{
- GtkEventBoxClass parent_class;
+ GtkHBoxClass parent_class;
void (*error) (BaconVideoWidget * bvw, const char *message);
void (*eos) (BaconVideoWidget * bvw);
diff --git a/libcesarplayer/src/baconvideowidget-marshal.c b/libcesarplayer/baconvideowidget-marshal.c
similarity index 98%
rename from libcesarplayer/src/baconvideowidget-marshal.c
rename to libcesarplayer/baconvideowidget-marshal.c
index 6b34127..e914ccd 100644
--- a/libcesarplayer/src/baconvideowidget-marshal.c
+++ b/libcesarplayer/baconvideowidget-marshal.c
@@ -1,247 +1,247 @@
-
-#ifndef __baconvideowidget_marshal_MARSHAL_H__
-#define __baconvideowidget_marshal_MARSHAL_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#ifdef G_ENABLE_DEBUG
-#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
-#define g_marshal_value_peek_char(v) g_value_get_schar (v)
-#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
-#define g_marshal_value_peek_int(v) g_value_get_int (v)
-#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
-#define g_marshal_value_peek_long(v) g_value_get_long (v)
-#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
-#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
-#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
-#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
-#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
-#define g_marshal_value_peek_float(v) g_value_get_float (v)
-#define g_marshal_value_peek_double(v) g_value_get_double (v)
-#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
-#define g_marshal_value_peek_param(v) g_value_get_param (v)
-#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
-#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
-#define g_marshal_value_peek_object(v) g_value_get_object (v)
-#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
-#else /* !G_ENABLE_DEBUG */
-/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
- * Do not access GValues directly in your code. Instead, use the
- * g_value_get_*() functions
- */
-#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
-#define g_marshal_value_peek_char(v) (v)->data[0].v_int
-#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
-#define g_marshal_value_peek_int(v) (v)->data[0].v_int
-#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
-#define g_marshal_value_peek_long(v) (v)->data[0].v_long
-#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
-#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
-#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
-#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
-#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
-#define g_marshal_value_peek_float(v) (v)->data[0].v_float
-#define g_marshal_value_peek_double(v) (v)->data[0].v_double
-#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
-#endif /* !G_ENABLE_DEBUG */
-
-
-/* VOID:INT64,INT64,DOUBLE,BOOLEAN (./baconvideowidget-marshal.list:1) */
-extern void baconvideowidget_marshal_VOID__INT64_INT64_DOUBLE_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-void
-baconvideowidget_marshal_VOID__INT64_INT64_DOUBLE_BOOLEAN (GClosure *closure,
- GValue *return_value G_GNUC_UNUSED,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint G_GNUC_UNUSED,
- gpointer marshal_data)
-{
- typedef void (*GMarshalFunc_VOID__INT64_INT64_DOUBLE_BOOLEAN) (gpointer data1,
- gint64 arg_1,
- gint64 arg_2,
- gdouble arg_3,
- gboolean arg_4,
- gpointer data2);
- register GMarshalFunc_VOID__INT64_INT64_DOUBLE_BOOLEAN callback;
- register GCClosure *cc = (GCClosure*) closure;
- register gpointer data1, data2;
-
- g_return_if_fail (n_param_values == 5);
-
- if (G_CCLOSURE_SWAP_DATA (closure))
- {
- data1 = closure->data;
- data2 = g_value_peek_pointer (param_values + 0);
- }
- else
- {
- data1 = g_value_peek_pointer (param_values + 0);
- data2 = closure->data;
- }
- callback = (GMarshalFunc_VOID__INT64_INT64_DOUBLE_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
-
- callback (data1,
- g_marshal_value_peek_int64 (param_values + 1),
- g_marshal_value_peek_int64 (param_values + 2),
- g_marshal_value_peek_double (param_values + 3),
- g_marshal_value_peek_boolean (param_values + 4),
- data2);
-}
-
-/* VOID:STRING,BOOLEAN,BOOLEAN (./baconvideowidget-marshal.list:2) */
-extern void baconvideowidget_marshal_VOID__STRING_BOOLEAN_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-void
-baconvideowidget_marshal_VOID__STRING_BOOLEAN_BOOLEAN (GClosure *closure,
- GValue *return_value G_GNUC_UNUSED,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint G_GNUC_UNUSED,
- gpointer marshal_data)
-{
- typedef void (*GMarshalFunc_VOID__STRING_BOOLEAN_BOOLEAN) (gpointer data1,
- gpointer arg_1,
- gboolean arg_2,
- gboolean arg_3,
- gpointer data2);
- register GMarshalFunc_VOID__STRING_BOOLEAN_BOOLEAN callback;
- register GCClosure *cc = (GCClosure*) closure;
- register gpointer data1, data2;
-
- g_return_if_fail (n_param_values == 4);
-
- if (G_CCLOSURE_SWAP_DATA (closure))
- {
- data1 = closure->data;
- data2 = g_value_peek_pointer (param_values + 0);
- }
- else
- {
- data1 = g_value_peek_pointer (param_values + 0);
- data2 = closure->data;
- }
- callback = (GMarshalFunc_VOID__STRING_BOOLEAN_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
-
- callback (data1,
- g_marshal_value_peek_string (param_values + 1),
- g_marshal_value_peek_boolean (param_values + 2),
- g_marshal_value_peek_boolean (param_values + 3),
- data2);
-}
-
-/* BOOLEAN:BOXED,BOXED,BOOLEAN (./baconvideowidget-marshal.list:3) */
-extern void baconvideowidget_marshal_BOOLEAN__BOXED_BOXED_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-void
-baconvideowidget_marshal_BOOLEAN__BOXED_BOXED_BOOLEAN (GClosure *closure,
- GValue *return_value G_GNUC_UNUSED,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint G_GNUC_UNUSED,
- gpointer marshal_data)
-{
- typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED_BOXED_BOOLEAN) (gpointer data1,
- gpointer arg_1,
- gpointer arg_2,
- gboolean arg_3,
- gpointer data2);
- register GMarshalFunc_BOOLEAN__BOXED_BOXED_BOOLEAN callback;
- register GCClosure *cc = (GCClosure*) closure;
- register gpointer data1, data2;
- gboolean v_return;
-
- g_return_if_fail (return_value != NULL);
- g_return_if_fail (n_param_values == 4);
-
- if (G_CCLOSURE_SWAP_DATA (closure))
- {
- data1 = closure->data;
- data2 = g_value_peek_pointer (param_values + 0);
- }
- else
- {
- data1 = g_value_peek_pointer (param_values + 0);
- data2 = closure->data;
- }
- callback = (GMarshalFunc_BOOLEAN__BOXED_BOXED_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
-
- v_return = callback (data1,
- g_marshal_value_peek_boxed (param_values + 1),
- g_marshal_value_peek_boxed (param_values + 2),
- g_marshal_value_peek_boolean (param_values + 3),
- data2);
-
- g_value_set_boolean (return_value, v_return);
-}
-
-/* VOID:INT64,INT64,FLOAT,BOOLEAN (./baconvideowidget-marshal.list:4) */
-extern void baconvideowidget_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-void
-baconvideowidget_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN (GClosure *closure,
- GValue *return_value G_GNUC_UNUSED,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint G_GNUC_UNUSED,
- gpointer marshal_data)
-{
- typedef void (*GMarshalFunc_VOID__INT64_INT64_FLOAT_BOOLEAN) (gpointer data1,
- gint64 arg_1,
- gint64 arg_2,
- gfloat arg_3,
- gboolean arg_4,
- gpointer data2);
- register GMarshalFunc_VOID__INT64_INT64_FLOAT_BOOLEAN callback;
- register GCClosure *cc = (GCClosure*) closure;
- register gpointer data1, data2;
-
- g_return_if_fail (n_param_values == 5);
-
- if (G_CCLOSURE_SWAP_DATA (closure))
- {
- data1 = closure->data;
- data2 = g_value_peek_pointer (param_values + 0);
- }
- else
- {
- data1 = g_value_peek_pointer (param_values + 0);
- data2 = closure->data;
- }
- callback = (GMarshalFunc_VOID__INT64_INT64_FLOAT_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
-
- callback (data1,
- g_marshal_value_peek_int64 (param_values + 1),
- g_marshal_value_peek_int64 (param_values + 2),
- g_marshal_value_peek_float (param_values + 3),
- g_marshal_value_peek_boolean (param_values + 4),
- data2);
-}
-
-G_END_DECLS
-
-#endif /* __baconvideowidget_marshal_MARSHAL_H__ */
-
+
+#ifndef __baconvideowidget_marshal_MARSHAL_H__
+#define __baconvideowidget_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_schar (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:INT64,INT64,DOUBLE,BOOLEAN (./baconvideowidget-marshal.list:1) */
+extern void baconvideowidget_marshal_VOID__INT64_INT64_DOUBLE_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+void
+baconvideowidget_marshal_VOID__INT64_INT64_DOUBLE_BOOLEAN (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__INT64_INT64_DOUBLE_BOOLEAN) (gpointer data1,
+ gint64 arg_1,
+ gint64 arg_2,
+ gdouble arg_3,
+ gboolean arg_4,
+ gpointer data2);
+ register GMarshalFunc_VOID__INT64_INT64_DOUBLE_BOOLEAN callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 5);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__INT64_INT64_DOUBLE_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_int64 (param_values + 1),
+ g_marshal_value_peek_int64 (param_values + 2),
+ g_marshal_value_peek_double (param_values + 3),
+ g_marshal_value_peek_boolean (param_values + 4),
+ data2);
+}
+
+/* VOID:STRING,BOOLEAN,BOOLEAN (./baconvideowidget-marshal.list:2) */
+extern void baconvideowidget_marshal_VOID__STRING_BOOLEAN_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+void
+baconvideowidget_marshal_VOID__STRING_BOOLEAN_BOOLEAN (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_BOOLEAN_BOOLEAN) (gpointer data1,
+ gpointer arg_1,
+ gboolean arg_2,
+ gboolean arg_3,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_BOOLEAN_BOOLEAN callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 4);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_BOOLEAN_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_string (param_values + 1),
+ g_marshal_value_peek_boolean (param_values + 2),
+ g_marshal_value_peek_boolean (param_values + 3),
+ data2);
+}
+
+/* BOOLEAN:BOXED,BOXED,BOOLEAN (./baconvideowidget-marshal.list:3) */
+extern void baconvideowidget_marshal_BOOLEAN__BOXED_BOXED_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+void
+baconvideowidget_marshal_BOOLEAN__BOXED_BOXED_BOOLEAN (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED_BOXED_BOOLEAN) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gboolean arg_3,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__BOXED_BOXED_BOOLEAN callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 4);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__BOXED_BOXED_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ g_marshal_value_peek_boxed (param_values + 2),
+ g_marshal_value_peek_boolean (param_values + 3),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* VOID:INT64,INT64,FLOAT,BOOLEAN (./baconvideowidget-marshal.list:4) */
+extern void baconvideowidget_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+void
+baconvideowidget_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__INT64_INT64_FLOAT_BOOLEAN) (gpointer data1,
+ gint64 arg_1,
+ gint64 arg_2,
+ gfloat arg_3,
+ gboolean arg_4,
+ gpointer data2);
+ register GMarshalFunc_VOID__INT64_INT64_FLOAT_BOOLEAN callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 5);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__INT64_INT64_FLOAT_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_int64 (param_values + 1),
+ g_marshal_value_peek_int64 (param_values + 2),
+ g_marshal_value_peek_float (param_values + 3),
+ g_marshal_value_peek_boolean (param_values + 4),
+ data2);
+}
+
+G_END_DECLS
+
+#endif /* __baconvideowidget_marshal_MARSHAL_H__ */
+
diff --git a/libcesarplayer/src/baconvideowidget-marshal.h b/libcesarplayer/baconvideowidget-marshal.h
similarity index 98%
rename from libcesarplayer/src/baconvideowidget-marshal.h
rename to libcesarplayer/baconvideowidget-marshal.h
index 035d853..7cba5d9 100644
--- a/libcesarplayer/src/baconvideowidget-marshal.h
+++ b/libcesarplayer/baconvideowidget-marshal.h
@@ -1,44 +1,44 @@
-
-#ifndef __baconvideowidget_marshal_MARSHAL_H__
-#define __baconvideowidget_marshal_MARSHAL_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-/* VOID:INT64,INT64,DOUBLE,BOOLEAN (./baconvideowidget-marshal.list:1) */
-extern void baconvideowidget_marshal_VOID__INT64_INT64_DOUBLE_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-
-/* VOID:STRING,BOOLEAN,BOOLEAN (./baconvideowidget-marshal.list:2) */
-extern void baconvideowidget_marshal_VOID__STRING_BOOLEAN_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-
-/* BOOLEAN:BOXED,BOXED,BOOLEAN (./baconvideowidget-marshal.list:3) */
-extern void baconvideowidget_marshal_BOOLEAN__BOXED_BOXED_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-
-/* VOID:INT64,INT64,FLOAT,BOOLEAN (./baconvideowidget-marshal.list:4) */
-extern void baconvideowidget_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-
-G_END_DECLS
-
-#endif /* __baconvideowidget_marshal_MARSHAL_H__ */
-
+
+#ifndef __baconvideowidget_marshal_MARSHAL_H__
+#define __baconvideowidget_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:INT64,INT64,DOUBLE,BOOLEAN (./baconvideowidget-marshal.list:1) */
+extern void baconvideowidget_marshal_VOID__INT64_INT64_DOUBLE_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:STRING,BOOLEAN,BOOLEAN (./baconvideowidget-marshal.list:2) */
+extern void baconvideowidget_marshal_VOID__STRING_BOOLEAN_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* BOOLEAN:BOXED,BOXED,BOOLEAN (./baconvideowidget-marshal.list:3) */
+extern void baconvideowidget_marshal_BOOLEAN__BOXED_BOXED_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:INT64,INT64,FLOAT,BOOLEAN (./baconvideowidget-marshal.list:4) */
+extern void baconvideowidget_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+G_END_DECLS
+
+#endif /* __baconvideowidget_marshal_MARSHAL_H__ */
+
diff --git a/libcesarplayer/src/baconvideowidget-marshal.list b/libcesarplayer/baconvideowidget-marshal.list
similarity index 100%
rename from libcesarplayer/src/baconvideowidget-marshal.list
rename to libcesarplayer/baconvideowidget-marshal.list
diff --git a/libcesarplayer/src/common.h b/libcesarplayer/common.h
similarity index 78%
rename from libcesarplayer/src/common.h
rename to libcesarplayer/common.h
index cb3ed97..c524ac8 100644
--- a/libcesarplayer/src/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 "d3dvideosink"
+#define BACKUP_VIDEO_SINK "autovideosink"
+#elif defined(OSTYPE_OS_X)
+#define DEFAULT_VIDEO_SINK "osxvideosink"
+#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 "osxvideosrc"
+#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
new file mode 100644
index 0000000..e055d84
--- /dev/null
+++ b/libcesarplayer/gst-camera-capturer.c
@@ -0,0 +1,2111 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+* Gstreamer DV capturer
+* Copyright (C) Andoni Morales Alastruey 2008 <ylatuya gmail com>
+*
+* Gstreamer DV capturer is free software.
+*
+* 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 <string.h>
+#include <stdio.h>
+
+#include <gst/app/gstappsrc.h>
+#include <gst/interfaces/xoverlay.h>
+#include <gst/interfaces/propertyprobe.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include "gst-camera-capturer.h"
+#include "gstscreenshot.h"
+#include "common.h"
+#include "video-utils.h"
+
+
+/* gtk+/gnome */
+#include <gdk/gdk.h>
+#if defined (GDK_WINDOWING_X11)
+#include <gdk/gdkx.h>
+#elif defined (GDK_WINDOWING_WIN32)
+#include <gdk/gdkwin32.h>
+#elif defined (GDK_WINDOWING_QUARTZ)
+#include <gdk/gdkquartz.h>
+#endif
+#include <gtk/gtk.h>
+
+GST_DEBUG_CATEGORY (_cesarplayer_gst_debug_cat);
+#define GST_CAT_DEFAULT _cesarplayer_gst_debug_cat
+
+/* Signals */
+enum
+{
+ SIGNAL_ERROR,
+ SIGNAL_EOS,
+ SIGNAL_STATE_CHANGED,
+ SIGNAL_DEVICE_CHANGE,
+ LAST_SIGNAL
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_OUTPUT_HEIGHT,
+ PROP_OUTPUT_WIDTH,
+ PROP_VIDEO_BITRATE,
+ PROP_AUDIO_BITRATE,
+ PROP_AUDIO_ENABLED,
+ PROP_OUTPUT_FILE,
+ PROP_DEVICE_ID,
+};
+
+struct GstCameraCapturerPrivate
+{
+
+ /*Encoding properties */
+ gchar *output_file;
+ gchar *device_id;
+ guint output_height;
+ guint output_width;
+ 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 */
+ gint video_height; /* Movie height */
+ const GValue *movie_par; /* Movie pixel aspect ratio */
+ gint video_width_pixels; /* Scaled movie width */
+ gint video_height_pixels; /* Scaled movie height */
+ gint video_fps_n;
+ gint video_fps_d;
+ gboolean media_has_video;
+ gboolean media_has_audio;
+
+ /* Snapshots */
+ GstBuffer *last_buffer;
+
+ /*GStreamer elements */
+ GstElement *main_pipeline;
+ 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 */
+ guintptr window_handle;
+
+ /*Videobox */
+ gboolean logo_mode;
+ GdkPixbuf *logo_pixbuf;
+ gboolean expand_logo;
+
+ /*GStreamer bus */
+ GstBus *bus;
+ gulong sig_bus_async;
+ gulong sig_bus_sync;
+};
+
+static GtkWidgetClass *parent_class = NULL;
+
+static GThread *gui_thread;
+
+static int gcc_signals[LAST_SIGNAL] = { 0 };
+
+static void gcc_error_msg (GstCameraCapturer * gcc, GstMessage * msg);
+static void gcc_bus_message_cb (GstBus * bus, GstMessage * message,
+ gpointer data);
+static void gst_camera_capturer_get_property (GObject * object,
+ guint property_id, GValue * value, GParamSpec * pspec);
+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 int gcc_get_video_stream_info (GstCameraCapturer * gcc);
+
+G_DEFINE_TYPE (GstCameraCapturer, gst_camera_capturer, GTK_TYPE_DRAWING_AREA);
+
+/***********************************
+*
+* GTK Widget
+*
+************************************/
+
+static gboolean
+gst_camera_capturer_configure_event (GtkWidget * widget,
+ GdkEventConfigure * event, GstCameraCapturer * gcc)
+{
+ GstXOverlay *xoverlay = NULL;
+
+ g_return_val_if_fail (gcc != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+
+ xoverlay = gcc->priv->xoverlay;
+
+ if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
+ gst_x_overlay_expose (xoverlay);
+ }
+
+ return FALSE;
+}
+
+static void
+gst_camera_capturer_realize_event (GtkWidget * widget)
+{
+ GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
+ GdkWindow *window = gtk_widget_get_window (widget);
+
+ if (!gdk_window_ensure_native (window))
+ g_error ("Couldn't create native window needed for GstXOverlay!");
+
+ /* Connect to configure event on the top level window */
+ g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
+ "configure-event", G_CALLBACK (gst_camera_capturer_configure_event), gcc);
+
+ gcc->priv->window_handle = gst_get_window_handle (window);
+}
+
+static gboolean
+gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
+{
+ GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
+ GstXOverlay *xoverlay;
+ gboolean draw_logo;
+ GdkWindow *win;
+
+ if (event && event->count > 0)
+ return TRUE;
+
+ if (event == NULL)
+ return TRUE;
+
+ xoverlay = gcc->priv->xoverlay;
+ if (xoverlay != NULL) {
+ gst_object_ref (xoverlay);
+ gst_set_window_handle (xoverlay, gcc->priv->window_handle);
+ }
+
+ win = gtk_widget_get_window (widget);
+
+ /* if there's only audio and no visualisation, draw the logo as well */
+ draw_logo = gcc->priv->media_has_audio && !gcc->priv->media_has_video;
+
+ if (gcc->priv->logo_mode || draw_logo) {
+ /* Start with a nice black canvas */
+ gdk_draw_rectangle (win, gtk_widget_get_style (widget)->black_gc, TRUE, 0,
+ 0, widget->allocation.width, widget->allocation.height);
+
+ if (gcc->priv->logo_pixbuf != NULL) {
+ GdkPixbuf *frame;
+ /*GdkPixbuf *drawing;*/
+ guchar *pixels;
+ int rowstride;
+ gint width, height, alloc_width, alloc_height, logo_x, logo_y;
+ gfloat ratio;
+
+ /* Checking if allocated space is smaller than our logo */
+
+
+ width = gdk_pixbuf_get_width (gcc->priv->logo_pixbuf);
+ height = gdk_pixbuf_get_height (gcc->priv->logo_pixbuf);
+ alloc_width = widget->allocation.width;
+ alloc_height = widget->allocation.height;
+
+ if ((gfloat) alloc_width / width > (gfloat) alloc_height / height) {
+ ratio = (gfloat) alloc_height / height;
+ } else {
+ ratio = (gfloat) alloc_width / width;
+ }
+
+ width *= ratio;
+ height *= ratio;
+
+ logo_x = (alloc_width / 2) - (width / 2);
+ logo_y = (alloc_height / 2) - (height / 2);
+
+
+ /* Drawing our frame */
+
+ if (gcc->priv->expand_logo) { // && !gcc->priv->drawing_mode) {
+ /* Scaling to available space */
+
+ frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ FALSE, 8, widget->allocation.width, widget->allocation.height);
+
+ gdk_pixbuf_composite (gcc->priv->logo_pixbuf,
+ frame,
+ 0, 0,
+ alloc_width, alloc_height,
+ logo_x, logo_y, ratio, ratio, GDK_INTERP_BILINEAR, 255);
+
+ rowstride = gdk_pixbuf_get_rowstride (frame);
+
+ pixels = gdk_pixbuf_get_pixels (frame) +
+ rowstride * event->area.y + event->area.x * 3;
+
+ gdk_draw_rgb_image_dithalign (widget->window,
+ widget->style->black_gc,
+ event->area.x, event->area.y,
+ event->area.width,
+ event->area.height,
+ GDK_RGB_DITHER_NORMAL, pixels,
+ rowstride, event->area.x, event->area.y);
+
+ g_object_unref (frame);
+ } else {
+ if (width <= 1 || height <= 1) {
+ if (xoverlay != NULL)
+ gst_object_unref (xoverlay);
+ gdk_window_end_paint (win);
+ return TRUE;
+ }
+
+ frame = gdk_pixbuf_scale_simple (gcc->priv->logo_pixbuf,
+ width, height, GDK_INTERP_BILINEAR);
+ gdk_draw_pixbuf (win, gtk_widget_get_style (widget)->fg_gc[0],
+ frame, 0, 0, logo_x, logo_y, width, height,
+ GDK_RGB_DITHER_NONE, 0, 0);
+
+ /*if (gcc->priv->drawing_mode && bvw->priv->drawing_pixbuf != NULL) {*/
+ /*drawing =*/
+ /*gdk_pixbuf_scale_simple (gcc->priv->drawing_pixbuf, width,*/
+ /*height, GDK_INTERP_BILINEAR);*/
+ /*gdk_draw_pixbuf (win,*/
+ /*gtk_widget_get_style (widget)->fg_gc[0],*/
+ /*drawing, 0, 0, logo_x, logo_y, width,*/
+ /*height, GDK_RGB_DITHER_NONE, 0, 0);*/
+ /*g_object_unref (drawing);*/
+ /*}*/
+
+ g_object_unref (frame);
+ }
+ } else if (win) {
+ /* No pixbuf, just draw a black background then */
+ gdk_window_clear_area (win,
+ 0, 0, widget->allocation.width, widget->allocation.height);
+ }
+ } else {
+ /* no logo, pass the expose to gst */
+ if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)){
+ gst_x_overlay_expose (xoverlay);
+ }
+ else {
+ /* No xoverlay to expose yet */
+ gdk_window_clear_area (win,
+ 0, 0, widget->allocation.width, widget->allocation.height);
+ }
+ }
+ if (xoverlay != NULL)
+ gst_object_unref (xoverlay);
+
+ 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->output_height = 480;
+ priv->output_width = 640;
+ priv->audio_bitrate = 128;
+ priv->video_bitrate = 5000;
+ priv->last_buffer = NULL;
+ priv->expand_logo = TRUE;
+ 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;
+
+ gtk_widget_add_events (GTK_WIDGET (object),
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
+
+ g_signal_connect (GTK_WIDGET (object), "realize",
+ G_CALLBACK (gst_camera_capturer_realize_event), NULL);
+}
+
+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->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_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)
+{
+ GstCameraCapturer *gcc;
+
+ gcc = GST_CAMERA_CAPTURER (object);
+
+ switch (property_id) {
+ case PROP_OUTPUT_HEIGHT:
+ gcc->priv->output_height = g_value_get_uint (value);
+ break;
+ case PROP_OUTPUT_WIDTH:
+ gcc->priv->output_width = g_value_get_uint (value);
+ break;
+ case PROP_VIDEO_BITRATE:
+ gst_camera_capturer_set_video_bit_rate (gcc, g_value_get_uint (value));
+ break;
+ case PROP_AUDIO_BITRATE:
+ gst_camera_capturer_set_audio_bit_rate (gcc, g_value_get_uint (value));
+ break;
+ case PROP_AUDIO_ENABLED:
+ gst_camera_capturer_set_audio_enabled (gcc, g_value_get_boolean (value));
+ break;
+ case PROP_OUTPUT_FILE:
+ gst_camera_capturer_set_output_file (gcc, g_value_get_string (value));
+ break;
+ case PROP_DEVICE_ID:
+ gst_camera_capturer_set_device_id (gcc, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_camera_capturer_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstCameraCapturer *gcc;
+
+ gcc = GST_CAMERA_CAPTURER (object);
+
+ switch (property_id) {
+ case PROP_OUTPUT_HEIGHT:
+ g_value_set_uint (value, gcc->priv->output_height);
+ break;
+ case PROP_OUTPUT_WIDTH:
+ g_value_set_uint (value, gcc->priv->output_width);
+ break;
+ case PROP_AUDIO_BITRATE:
+ g_value_set_uint (value, gcc->priv->audio_bitrate);
+ break;
+ case PROP_VIDEO_BITRATE:
+ g_value_set_uint (value, gcc->priv->video_bitrate);
+ break;
+ case PROP_AUDIO_ENABLED:
+ g_value_set_boolean (value, gcc->priv->audio_enabled);
+ break;
+ case PROP_OUTPUT_FILE:
+ g_value_set_string (value, gcc->priv->output_file);
+ break;
+ case PROP_DEVICE_ID:
+ g_value_set_string (value, gcc->priv->device_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_camera_capturer_class_init (GstCameraCapturerClass * klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = (GObjectClass *) klass;
+ widget_class = (GtkWidgetClass *) klass;
+ parent_class = g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (object_class, sizeof (GstCameraCapturerPrivate));
+
+ /* GtkWidget */
+ widget_class->expose_event = gst_camera_capturer_expose_event;
+
+ /* GObject */
+ object_class->set_property = gst_camera_capturer_set_property;
+ object_class->get_property = gst_camera_capturer_get_property;
+ object_class->finalize = gst_camera_capturer_finalize;
+
+ /* Properties */
+ g_object_class_install_property (object_class, PROP_OUTPUT_HEIGHT,
+ g_param_spec_uint ("output_height", NULL,
+ NULL, 0, 5600, 576, G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_OUTPUT_WIDTH,
+ g_param_spec_uint ("output_width", NULL,
+ NULL, 0, 5600, 720, G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_VIDEO_BITRATE,
+ g_param_spec_uint ("video_bitrate", NULL,
+ NULL, 100, G_MAXUINT, 1000, G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_AUDIO_BITRATE,
+ g_param_spec_uint ("audio_bitrate", NULL,
+ NULL, 12, G_MAXUINT, 128, G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_AUDIO_ENABLED,
+ g_param_spec_boolean ("audio_enabled", NULL,
+ NULL, FALSE, G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_OUTPUT_FILE,
+ g_param_spec_string ("output_file", NULL,
+ NULL, FALSE, G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_DEVICE_ID,
+ g_param_spec_string ("device_id", NULL, NULL, FALSE, G_PARAM_READWRITE));
+
+ /* Signals */
+ gcc_signals[SIGNAL_ERROR] =
+ g_signal_new ("error",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstCameraCapturerClass, error),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ gcc_signals[SIGNAL_EOS] =
+ g_signal_new ("eos",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstCameraCapturerClass, eos),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ gcc_signals[SIGNAL_DEVICE_CHANGE] =
+ g_signal_new ("device-change",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstCameraCapturerClass, device_change),
+ 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)
+{
+ gst_init (argc, argv);
+}
+
+GQuark
+gst_camera_capturer_error_quark (void)
+{
+ static GQuark q; /* 0 */
+
+ if (G_UNLIKELY (q == 0)) {
+ q = g_quark_from_static_string ("gcc-error-quark");
+ }
+ return q;
+}
+
+gboolean
+gst_camera_capture_videosrc_buffer_probe (GstPad * pad, GstBuffer * buf,
+ gpointer data)
+{
+ GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (data);
+
+ if (gcc->priv->last_buffer) {
+ gst_buffer_unref (gcc->priv->last_buffer);
+ gcc->priv->last_buffer = NULL;
+ }
+
+ gst_buffer_ref (buf);
+ gcc->priv->last_buffer = buf;
+
+ return TRUE;
+}
+
+static void
+gst_camera_capturer_update_device_id (GstCameraCapturer *gcc)
+{
+ const gchar *prop_name;
+
+ 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, "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_object_unref (sink);
+ }
+ 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));
+ }
+
+ 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));
+ }
+}
+
+static GstElement *
+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 */
+ 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_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 */
+ 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;
+}
+
+static GstElement *
+gst_camera_capturer_prepare_mpegts_source (GstCameraCapturer *gcc)
+{
+ GstElement *bin, *demuxer, *video, *video_parser;
+ GstPad *video_pad, *src_pad;
+
+ GST_INFO_OBJECT (gcc, "Creating mpegts source");
+
+ gcc->priv->video_needs_keyframe_sync = TRUE;
+ gcc->priv->video_synced = FALSE;
+
+ /* 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);
+
+ 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_signal_connect (demuxer, "pad-added", G_CALLBACK (cb_new_pad), gcc);
+
+ gst_camera_capturer_create_remuxer_bin(gcc);
+
+ return bin;
+}
+
+static gboolean
+gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
+ GstBuffer *prev_buf, gboolean is_video)
+{
+ GstClockTime buf_ts, new_buf_ts, duration;
+ GstBuffer *enc_buf;
+
+ g_mutex_lock(gcc->priv->recording_lock);
+
+ 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 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;
+ }
+ }
+
+ 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));
+ }
+
+ /* 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;
+ }
+
+ 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;
+
+ /* 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;
+
+ /* 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;
+ }
+
+ GST_BUFFER_TIMESTAMP (enc_buf) = new_buf_ts;
+
+ 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));
+
+ 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);
+
+done:
+ {
+ g_mutex_unlock(gcc->priv->recording_lock);
+ return TRUE;
+ }
+}
+
+static gboolean
+gst_camera_capturer_audio_encoding_probe (GstPad *pad, GstBuffer *buf,
+ GstCameraCapturer *gcc)
+{
+ return gst_camera_capturer_encoding_retimestamper(gcc, buf, FALSE);
+}
+
+static gboolean
+gst_camera_capturer_video_encoding_probe (GstPad *pad, GstBuffer *buf,
+ GstCameraCapturer *gcc)
+{
+ return gst_camera_capturer_encoding_retimestamper(gcc, buf, TRUE);
+}
+
+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);
+ }
+}
+
+static void
+gst_camera_capturer_link_encoder_bin (GstCameraCapturer *gcc)
+{
+ GstPad *v_dec_pad, *v_enc_pad;
+
+ 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);
+}
+
+static void
+gst_camera_capturer_link_preview (GstCameraCapturer *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;
+
+ 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);
+}
+
+static gboolean
+cb_last_buffer (GstPad *pad, GstBuffer *buf, GstCameraCapturer *gcc){
+ if (buf != NULL) {
+ if (gcc->priv->last_buffer != NULL)
+ gst_buffer_unref(buf);
+ gst_buffer_ref(buf);
+ gcc->priv->last_buffer = buf;
+ }
+ return TRUE;
+}
+
+static void
+cb_new_prev_pad (GstElement * element, GstPad * pad, GstElement *bin)
+{
+ GstPad *sink_pad;
+
+ sink_pad = gst_element_get_static_pad(bin, "sink");
+ gst_pad_link(pad, sink_pad);
+ gst_object_unref(sink_pad);
+}
+
+static void
+gst_camera_capturer_create_preview(GstCameraCapturer *gcc)
+{
+ GstElement *v_decoder, *video_bin;
+ GstPad *video_pad;
+
+ 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);
+
+ video_pad = gst_element_get_static_pad(video_bin, "sink");
+ gst_pad_add_buffer_probe (video_pad, (GCallback) cb_last_buffer, gcc);
+ gst_object_unref(video_pad);
+
+ /* 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);
+}
+
+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();
+ }
+
+ /* HACK: dshowvideosrc's device must be set before linking the element
+ * since the device is set in getcaps and can't be changed later */
+ if (!g_strcmp0 (gcc->priv->source_element_name, "dshowvideosrc"))
+ source_str = g_strdup_printf("%s device-name=\"%s\" name=source ! typefind name=typefind",
+ source_desc, gcc->priv->device_id);
+ else
+ source_str = g_strdup_printf("%s name=source ! typefind name=typefind", source_desc);
+ GST_INFO_OBJECT(gcc, "Created video source %s", source_str);
+ 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);
+
+ gst_object_unref (gcc->priv->source);
+ gst_object_unref (typefind);
+
+ return TRUE;
+}
+
+static gboolean
+gst_camera_capturer_create_video_encoder (GstCameraCapturer * gcc,
+ VideoEncoderType type, GError ** err)
+{
+ gchar *name = NULL;
+
+ g_return_val_if_fail (gcc != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+
+ switch (type) {
+ case VIDEO_ENCODER_MPEG4:
+ gcc->priv->video_enc =
+ gst_element_factory_make ("ffenc_mpeg4", "video-encoder");
+ 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->video_enc =
+ gst_element_factory_make ("xvidenc", "video-encoder");
+ 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->video_enc =
+ gst_element_factory_make ("x264enc", "video-encoder");
+ 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->video_enc =
+ gst_element_factory_make ("theoraenc", "video-encoder");
+ 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->video_enc =
+ gst_element_factory_make ("vp8enc", "video-encoder");
+ g_object_set (gcc->priv->video_enc, "speed", 2, "threads", 8,
+ "max-keyframe-distance", 25, NULL);
+ name = "VP8 video encoder";
+ break;
+
+ }
+ 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);
+ 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;
+}
+
+static gboolean
+gst_camera_capturer_create_audio_encoder (GstCameraCapturer * gcc,
+ AudioEncoderType type, GError ** err)
+{
+ gchar *name = NULL;
+
+ g_return_val_if_fail (gcc != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+
+ switch (type) {
+ case AUDIO_ENCODER_MP3:
+ gcc->priv->audio_enc =
+ gst_element_factory_make ("lamemp3enc", "audio-encoder");
+ g_object_set (gcc->priv->audio_enc, "target", 0, NULL);
+ name = "Mp3 audio encoder";
+ break;
+
+ case AUDIO_ENCODER_AAC:
+ gcc->priv->audio_enc = gst_element_factory_make ("faac", "audio-encoder");
+ name = "AAC audio encoder";
+ break;
+
+ case AUDIO_ENCODER_VORBIS:
+ default:
+ gcc->priv->audio_enc =
+ gst_element_factory_make ("vorbisenc", "audio-encoder");
+ name = "Vorbis audio encoder";
+ break;
+ }
+
+ 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);
+ 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;
+}
+
+static gboolean
+gst_camera_capturer_create_video_muxer (GstCameraCapturer * gcc,
+ VideoMuxerType type, GError ** err)
+{
+ gchar *name = NULL;
+
+ g_return_val_if_fail (gcc != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+
+ switch (type) {
+ case VIDEO_MUXER_OGG:
+ name = "OGG muxer";
+ gcc->priv->muxer = gst_element_factory_make ("oggmux", "video-muxer");
+ break;
+ case VIDEO_MUXER_AVI:
+ name = "AVI muxer";
+ gcc->priv->muxer = gst_element_factory_make ("avimux", "video-muxer");
+ break;
+ case VIDEO_MUXER_MATROSKA:
+ name = "Matroska muxer";
+ gcc->priv->muxer =
+ gst_element_factory_make ("matroskamux", "video-muxer");
+ break;
+ case VIDEO_MUXER_MP4:
+ name = "MP4 muxer";
+ gcc->priv->muxer = gst_element_factory_make ("qtmux", "video-muxer");
+ break;
+ case VIDEO_MUXER_WEBM:
+ default:
+ name = "WebM muxer";
+ gcc->priv->muxer = gst_element_factory_make ("webmmux", "video-muxer");
+ break;
+ }
+
+ 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);
+ }
+
+ 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;
+ GstMessageType msg_type;
+
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ msg_type = GST_MESSAGE_TYPE (message);
+
+ switch (msg_type) {
+ case GST_MESSAGE_ERROR:
+ {
+ if (gcc->priv->main_pipeline) {
+ gst_camera_capturer_stop (gcc);
+ gst_camera_capturer_close (gcc);
+ gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+ }
+ gcc_error_msg (gcc, message);
+ break;
+ }
+
+ case GST_MESSAGE_WARNING:
+ {
+ GST_WARNING ("Warning message: %" GST_PTR_FORMAT, message);
+ break;
+ }
+
+ case GST_MESSAGE_EOS:
+ {
+ GST_INFO_OBJECT (gcc, "EOS message");
+ g_signal_emit (gcc, gcc_signals[SIGNAL_EOS], 0);
+ break;
+ }
+
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ GstState old_state, new_state;
+
+ gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+
+ if (old_state == new_state)
+ break;
+
+ /* we only care about playbin (pipeline) state changes */
+ if (GST_MESSAGE_SRC (message) != GST_OBJECT (gcc->priv->main_pipeline))
+ break;
+
+ if (old_state == GST_STATE_PAUSED && new_state == GST_STATE_PLAYING) {
+ gcc_get_video_stream_info (gcc);
+ }
+ }
+
+ case GST_MESSAGE_ELEMENT:
+ {
+ const GstStructure *s;
+ gint device_change = 0;
+
+ /* We only care about messages sent by the device source */
+ if (GST_MESSAGE_SRC (message) != GST_OBJECT (gcc->priv->source))
+ break;
+
+ s = gst_message_get_structure (message);
+ /* check if it's bus reset message and it contains the
+ * 'current-device-change' field */
+ if (g_strcmp0 (gst_structure_get_name (s), "ieee1394-bus-reset"))
+ break;
+ if (!gst_structure_has_field (s, "current-device-change"))
+ break;
+
+
+ /* emit a signal if the device was connected or disconnected */
+ gst_structure_get_int (s, "current-device-change", &device_change);
+
+ if (device_change != 0)
+ g_signal_emit (gcc, gcc_signals[SIGNAL_DEVICE_CHANGE], 0,
+ device_change);
+ break;
+ }
+
+ default:
+ GST_LOG ("Unhandled message: %" GST_PTR_FORMAT, message);
+ break;
+ }
+}
+
+static void
+gcc_error_msg (GstCameraCapturer * gcc, 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 (gcc, gcc_signals[SIGNAL_ERROR], 0, err->message);
+ g_error_free (err);
+ }
+ g_free (dbg);
+}
+
+static void
+gcc_element_msg_sync (GstBus * bus, GstMessage * msg, gpointer data)
+{
+ GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (data);
+
+ g_assert (msg->type == GST_MESSAGE_ELEMENT);
+
+ if (msg->structure == NULL)
+ return;
+
+ /* This only gets sent if we haven't set an ID yet. This is our last
+ * chance to set it before the video sink will create its own window */
+ if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) {
+
+ if (gcc->priv->xoverlay == NULL) {
+ GstObject *sender = GST_MESSAGE_SRC (msg);
+ if (sender && GST_IS_X_OVERLAY (sender))
+ gcc->priv->xoverlay = GST_X_OVERLAY (gst_object_ref (sender));
+ }
+
+ g_return_if_fail (gcc->priv->xoverlay != NULL);
+ g_return_if_fail (gcc->priv->window_handle != 0);
+
+ g_object_set (GST_ELEMENT (gcc->priv->xoverlay), "force-aspect-ratio", TRUE, NULL);
+ gst_set_window_handle (gcc->priv->xoverlay, gcc->priv->window_handle);
+ gtk_widget_queue_draw (GTK_WIDGET(gcc));
+ }
+}
+
+static int
+gcc_get_video_stream_info (GstCameraCapturer * gcc)
+{
+ GstPad *sourcepad;
+ GstCaps *caps;
+ GstStructure *s;
+
+ sourcepad = gst_element_get_pad (gcc->priv->source_bin, "src");
+ caps = gst_pad_get_negotiated_caps (sourcepad);
+
+ if (!(caps)) {
+ GST_WARNING_OBJECT (gcc, "Could not get stream info");
+ return -1;
+ }
+
+ /* Get the source caps */
+ s = gst_caps_get_structure (caps, 0);
+ if (s) {
+ /* We need at least width/height and framerate */
+ if (!
+ (gst_structure_get_fraction
+ (s, "framerate", &gcc->priv->video_fps_n, &gcc->priv->video_fps_d)
+ && gst_structure_get_int (s, "width", &gcc->priv->video_width)
+ && gst_structure_get_int (s, "height", &gcc->priv->video_height)))
+ return -1;
+ /* Get the source PAR if available */
+ gcc->priv->movie_par = gst_structure_get_value (s, "pixel-aspect-ratio");
+ }
+ return 1;
+}
+
+/*****************************************************
+ *
+ * Device Probe
+ *
+ * **************************************************/
+
+GList *
+gst_camera_capturer_enum_devices (gchar * device_name)
+{
+ GstElement *device;
+ GstPropertyProbe *probe;
+ GValueArray *va;
+ gchar *prop_name;
+ GList *list = NULL;
+ guint i = 0;
+
+ device = gst_element_factory_make (device_name, "source");
+ if (!device || !GST_IS_PROPERTY_PROBE (device))
+ goto finish;
+ gst_element_set_state (device, GST_STATE_READY);
+ gst_element_get_state (device, NULL, NULL, 5 * GST_SECOND);
+ probe = GST_PROPERTY_PROBE (device);
+
+ if (!g_strcmp0 (device_name, "dv1394src"))
+ prop_name = "guid";
+ else if (!g_strcmp0 (device_name, "v4l2src") ||
+ !g_strcmp0 (device_name, "osxvideosrc"))
+ prop_name = "device";
+ else
+ prop_name = "device-name";
+
+ va = gst_property_probe_get_values_name (probe, prop_name);
+ if (!va)
+ goto finish;
+
+ for (i = 0; i < va->n_values; ++i) {
+ GValue *v = g_value_array_get_nth (va, i);
+ GValue valstr = { 0, };
+
+ g_value_init (&valstr, G_TYPE_STRING);
+ if (!g_value_transform (v, &valstr))
+ continue;
+ list = g_list_append (list, g_value_dup_string (&valstr));
+ g_value_unset (&valstr);
+ }
+ g_value_array_free (va);
+
+finish:
+ {
+ gst_element_set_state (device, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (device));
+ return list;
+ }
+}
+
+GList *
+gst_camera_capturer_enum_video_devices (void)
+{
+ return gst_camera_capturer_enum_devices (DVVIDEOSRC);
+}
+
+GList *
+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);
+
+ /* check for video */
+ if (!gcc->priv->media_has_video) {
+ g_set_error_literal (error, GCC_ERROR, GST_ERROR_GENERIC,
+ "Media contains no supported video streams.");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+destroy_pixbuf (guchar * pix, gpointer data)
+{
+ gst_buffer_unref (GST_BUFFER (data));
+}
+
+void
+gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf)
+{
+ g_object_unref (pixbuf);
+}
+
+GdkPixbuf *
+gst_camera_capturer_get_current_frame (GstCameraCapturer * gcc)
+{
+ GstStructure *s;
+ GdkPixbuf *pixbuf;
+ GstBuffer *last_buffer;
+ GstBuffer *buf;
+ GstCaps *to_caps;
+ gint outwidth = 0;
+ gint outheight = 0;
+
+ g_return_val_if_fail (gcc != NULL, NULL);
+ g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), NULL);
+
+ gst_element_get_state (gcc->priv->main_pipeline, NULL, NULL, -1);
+
+ /* no video info */
+ if (!gcc->priv->video_width || !gcc->priv->video_height) {
+ GST_DEBUG_OBJECT (gcc, "Could not take screenshot: %s", "no video info");
+ g_warning ("Could not take screenshot: %s", "no video info");
+ return NULL;
+ }
+
+ /* get frame */
+ last_buffer = gcc->priv->last_buffer;
+ gst_buffer_ref (last_buffer);
+
+ if (!last_buffer) {
+ GST_DEBUG_OBJECT (gcc, "Could not take screenshot: %s",
+ "no last video frame");
+ g_warning ("Could not take screenshot: %s", "no last video frame");
+ return NULL;
+ }
+
+ if (GST_BUFFER_CAPS (last_buffer) == NULL) {
+ GST_DEBUG_OBJECT (gcc, "Could not take screenshot: %s",
+ "no caps on buffer");
+ g_warning ("Could not take screenshot: %s", "no caps on buffer");
+ return NULL;
+ }
+
+ /* convert to our desired format (RGB24) */
+ to_caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24,
+ /* Note: we don't ask for a specific width/height here, so that
+ * videoscale can adjust dimensions from a non-1/1 pixel aspect
+ * ratio to a 1/1 pixel-aspect-ratio */
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, 1,
+ 1, "endianness", G_TYPE_INT, G_BIG_ENDIAN,
+ "red_mask", G_TYPE_INT, 0xff0000,
+ "green_mask", G_TYPE_INT, 0x00ff00,
+ "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
+
+ if (gcc->priv->video_fps_n > 0 && gcc->priv->video_fps_d > 0) {
+ gst_caps_set_simple (to_caps, "framerate", GST_TYPE_FRACTION,
+ gcc->priv->video_fps_n, gcc->priv->video_fps_d, NULL);
+ }
+
+ GST_DEBUG_OBJECT (gcc, "frame caps: %" GST_PTR_FORMAT,
+ GST_BUFFER_CAPS (gcc->priv->last_buffer));
+ GST_DEBUG_OBJECT (gcc, "pixbuf caps: %" GST_PTR_FORMAT, to_caps);
+
+ /* bvw_frame_conv_convert () takes ownership of the buffer passed */
+ buf = bvw_frame_conv_convert (last_buffer, to_caps);
+
+ gst_caps_unref (to_caps);
+ gst_buffer_unref (last_buffer);
+
+ if (!buf) {
+ GST_DEBUG_OBJECT (gcc, "Could not take screenshot: %s",
+ "conversion failed");
+ g_warning ("Could not take screenshot: %s", "conversion failed");
+ return NULL;
+ }
+
+ if (!GST_BUFFER_CAPS (buf)) {
+ GST_DEBUG_OBJECT (gcc, "Could not take screenshot: %s",
+ "no caps on output buffer");
+ g_warning ("Could not take screenshot: %s", "no caps on output buffer");
+ return NULL;
+ }
+
+ s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
+ gst_structure_get_int (s, "width", &outwidth);
+ gst_structure_get_int (s, "height", &outheight);
+ g_return_val_if_fail (outwidth > 0 && outheight > 0, NULL);
+
+ /* create pixbuf from that - we don't want to use the gstreamer's buffer
+ * because the GTK# bindings won't call the destroy funtion */
+ pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buf),
+ GDK_COLORSPACE_RGB, FALSE, 8, outwidth,
+ outheight, GST_ROUND_UP_4 (outwidth * 3), destroy_pixbuf, buf);
+
+ if (!pixbuf) {
+ GST_DEBUG_OBJECT (gcc, "Could not take screenshot: %s",
+ "could not create pixbuf");
+ g_warning ("Could not take screenshot: %s", "could not create pixbuf");
+ }
+
+ 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->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/src/gst-camera-capturer.h b/libcesarplayer/gst-camera-capturer.h
similarity index 58%
rename from libcesarplayer/src/gst-camera-capturer.h
rename to libcesarplayer/gst-camera-capturer.h
index 0e83bb5..b88982b 100644
--- a/libcesarplayer/src/gst-camera-capturer.h
+++ b/libcesarplayer/gst-camera-capturer.h
@@ -50,7 +50,7 @@ typedef struct GstCameraCapturerPrivate GstCameraCapturerPrivate;
struct _GstCameraCapturerClass
{
- GtkHBoxClass parent_class;
+ GtkDrawingAreaClass parent_class;
void (*eos) (GstCameraCapturer * gcc);
void (*error) (GstCameraCapturer * gcc, const char *message);
@@ -60,44 +60,29 @@ struct _GstCameraCapturerClass
struct _GstCameraCapturer
{
- GtkEventBox parent;
+ GtkDrawingArea parent;
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;
+EXPORT GType gst_camera_capturer_get_type (void) 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
+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 void gst_camera_capturer_set_source (GstCameraCapturer * gcc, CaptureSourceType source);
+EXPORT void gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc, VideoEncoderType encoder);
+EXPORT void gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc, AudioEncoderType encoder);
+EXPORT void gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc, VideoMuxerType muxer);
+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
* gcc);
- EXPORT void gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf);
- EXPORT void gst_camera_capturer_finalize (GObject * object);
+EXPORT void gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf);
+EXPORT void gst_camera_capturer_finalize (GObject * object);
G_END_DECLS
#endif /* _GST_CAMERA_CAPTURER_H_ */
diff --git a/libcesarplayer/gst-remuxer.c b/libcesarplayer/gst-remuxer.c
new file mode 100644
index 0000000..166996b
--- /dev/null
+++ b/libcesarplayer/gst-remuxer.c
@@ -0,0 +1,538 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+* Gstreamer Remuxer
+* Copyright (C) Andoni Morales Alastruey 2012 <ylatuya gmail com>
+*
+* LongoMatch is free software.
+*
+* 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.
+*
+* LongoMatch 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 <string.h>
+#include <stdio.h>
+
+#include <gst/gst.h>
+
+#include "gst-remuxer.h"
+
+GST_DEBUG_CATEGORY (_remuxer_gst_debug_cat);
+#define GST_CAT_DEFAULT _remuxer_gst_debug_cat
+
+/* Signals */
+enum
+{
+ SIGNAL_ERROR,
+ SIGNAL_PERCENT,
+ LAST_SIGNAL
+};
+
+struct GstRemuxerPrivate
+{
+
+ /*Encoding properties */
+ gchar *input_file;
+ gchar *output_file;
+ VideoMuxerType video_muxer_type;
+
+ /* Remuxer */
+ GstClockTime last_video_buf_ts;
+ GstClockTime last_audio_buf_ts;
+ gboolean audio_linked;
+ gboolean video_linked;
+
+ /*GStreamer elements */
+ GstElement *main_pipeline;
+
+ /*GStreamer bus */
+ GstBus *bus;
+ gulong sig_bus_async;
+};
+
+static GObject *parent_class = NULL;
+
+static int remuxer_signals[LAST_SIGNAL] = { 0 };
+
+static void remuxer_error_msg (GstRemuxer * remuxer, GstMessage * msg);
+static void remuxer_bus_message_cb (GstBus * bus, GstMessage * message,
+ gpointer data);
+
+G_DEFINE_TYPE (GstRemuxer, gst_remuxer, G_TYPE_OBJECT);
+
+/***********************************
+*
+* Class, Object and Properties
+*
+************************************/
+
+static void
+gst_remuxer_init (GstRemuxer * object)
+{
+ GstRemuxerPrivate *priv;
+ object->priv = priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_REMUXER,
+ GstRemuxerPrivate);
+
+ priv->input_file = NULL;
+ priv->output_file = NULL;
+ priv->last_video_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->last_audio_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->video_muxer_type = VIDEO_MUXER_WEBM;
+ priv->audio_linked = FALSE;
+ priv->video_linked = FALSE;
+}
+
+void
+gst_remuxer_finalize (GObject * object)
+{
+ GstRemuxer *remuxer = (GstRemuxer *) object;
+
+ GST_DEBUG_OBJECT (remuxer, "Finalizing.");
+ if (remuxer->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 (remuxer->priv->bus, TRUE);
+
+ if (remuxer->priv->sig_bus_async)
+ g_signal_handler_disconnect (remuxer->priv->bus, remuxer->priv->sig_bus_async);
+
+ gst_object_unref (remuxer->priv->bus);
+ remuxer->priv->bus = NULL;
+ }
+
+ if (remuxer->priv->input_file) {
+ g_free (remuxer->priv->input_file);
+ remuxer->priv->input_file = NULL;
+ }
+
+ if (remuxer->priv->output_file) {
+ g_free (remuxer->priv->output_file);
+ remuxer->priv->output_file = NULL;
+ }
+
+ if (remuxer->priv->main_pipeline != NULL
+ && GST_IS_ELEMENT (remuxer->priv->main_pipeline)) {
+ gst_element_set_state (remuxer->priv->main_pipeline,
+ GST_STATE_NULL);
+ gst_object_unref (remuxer->priv->main_pipeline);
+ remuxer->priv->main_pipeline = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_remuxer_class_init (GstRemuxerClass * klass)
+{
+ GObjectClass *object_class;
+
+ object_class = (GObjectClass *) klass;
+ parent_class = g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (object_class, sizeof (GstRemuxerPrivate));
+
+ object_class->finalize = gst_remuxer_finalize;
+
+ /* Signals */
+ remuxer_signals[SIGNAL_ERROR] =
+ g_signal_new ("error",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstRemuxerClass, error),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ remuxer_signals[SIGNAL_PERCENT] =
+ g_signal_new ("percent_completed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstRemuxerClass, percent_completed),
+ NULL, NULL, g_cclosure_marshal_VOID__FLOAT, G_TYPE_NONE, 1, G_TYPE_FLOAT);
+}
+
+/***********************************
+*
+* GStreamer
+*
+************************************/
+
+void
+gst_remuxer_init_backend (int *argc, char ***argv)
+{
+ gst_init (argc, argv);
+}
+
+GQuark
+gst_remuxer_error_quark (void)
+{
+ static GQuark q; /* 0 */
+
+ if (G_UNLIKELY (q == 0)) {
+ q = g_quark_from_static_string ("remuxer-error-quark");
+ }
+ return q;
+}
+
+static GstElement *
+gst_remuxer_create_video_muxer (GstRemuxer * remuxer,
+ VideoMuxerType type)
+{
+ GstElement *muxer;
+
+ g_return_val_if_fail (remuxer != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_REMUXER (remuxer), FALSE);
+
+ switch (type) {
+ case VIDEO_MUXER_OGG:
+ muxer = gst_element_factory_make ("oggmux", "muxer");
+ break;
+ case VIDEO_MUXER_AVI:
+ muxer = gst_element_factory_make ("avimux", "muxer");
+ break;
+ case VIDEO_MUXER_MATROSKA:
+ muxer = gst_element_factory_make ("matroskamux", "muxer");
+ break;
+ case VIDEO_MUXER_MP4:
+ muxer = gst_element_factory_make ("qtmux", "muxer");
+ break;
+ case VIDEO_MUXER_WEBM:
+ default:
+ muxer = gst_element_factory_make ("webmmux", "muxer");
+ break;
+ }
+
+ return muxer;
+}
+
+static gboolean
+gst_remuxer_fix_video_ts (GstPad *pad, GstBuffer *buf, GstRemuxer *remuxer)
+{
+ if (GST_BUFFER_TIMESTAMP (buf) == GST_CLOCK_TIME_NONE) {
+ GST_BUFFER_TIMESTAMP (buf) = remuxer->priv->last_video_buf_ts;
+ } else {
+ remuxer->priv->last_video_buf_ts = GST_BUFFER_TIMESTAMP (buf);
+ }
+ return TRUE;
+}
+
+static gboolean
+gst_remuxer_pad_added_cb (GstElement *demuxer, GstPad *pad,
+ GstRemuxer *remuxer)
+{
+ GstElement *muxer, *queue;
+ GstElement *parser = NULL;
+ GstPad *muxer_pad, *queue_sink_pad, *queue_src_pad;
+ GstCaps *caps, *parser_caps = NULL;
+ const GstStructure *s;
+ gchar *muxer_pad_name = NULL;
+ const gchar *mime;
+ gboolean is_video;
+
+ caps = gst_pad_get_caps_reffed (pad);
+ s = gst_caps_get_structure (caps, 0);
+ mime = gst_structure_get_name (s);
+ GST_INFO_OBJECT (remuxer, "Found mime type: %s", mime);
+
+ if (g_strrstr (mime, "video") && !remuxer->priv->video_linked) {
+ muxer_pad_name = "video_%d";
+ if (g_strrstr (mime, "video/x-h264")) {
+ GstPad *parser_pad;
+
+ parser = gst_element_factory_make("h264parse", "video-parser");
+ parser_caps = gst_caps_from_string("video/x-h264, stream-format=avc, alignment=au");
+
+ parser_pad = gst_element_get_static_pad (parser, "src");
+ gst_pad_add_buffer_probe (parser_pad, (GCallback)gst_remuxer_fix_video_ts, remuxer);
+ }
+ is_video = TRUE;
+ } else if (g_strrstr (mime, "audio") && !remuxer->priv->audio_linked) {
+ muxer_pad_name = "audio_%d";
+ if (g_strrstr (mime, "audio/mpeg")) {
+ gint version;
+ gst_structure_get_int (s, "mpegversion", &version);
+ if (version == 4) {
+ /* FIXME: aacparse doesn't seem to support adts to raw conversion */
+ //parser = gst_element_factory_make ("aacparse", NULL);
+ parser = gst_parse_bin_from_description ("faad ! faac", TRUE, NULL);
+ } else if (version == 3) {
+ parser = gst_element_factory_make("mp3parse", "audio-parser");
+ } else {
+ parser = gst_element_factory_make("mpegaudioparse", "audio-parser");
+ }
+ } else if (g_strrstr (mime, "audio/x-eac3")) {
+ parser = gst_element_factory_make ("ac3parse", NULL);
+ } else if (g_strrstr (mime, "audio/x-ac3")) {
+ parser = gst_element_factory_make ("ac3parse", NULL);
+ }
+ is_video = FALSE;
+ }
+
+ if (muxer_pad_name == NULL) {
+ gst_caps_unref (caps);
+ return TRUE;
+ }
+
+ muxer = gst_bin_get_by_name (GST_BIN(remuxer->priv->main_pipeline), "muxer");
+ if (parser != NULL) {
+ gst_bin_add (GST_BIN(remuxer->priv->main_pipeline), parser);
+ gst_element_set_state (parser, GST_STATE_PLAYING);
+ if (parser_caps) {
+ gst_element_link_filtered (parser, muxer, parser_caps);
+ gst_caps_unref (parser_caps);
+ } else {
+ gst_element_link (parser, muxer);
+ }
+ muxer_pad = gst_element_get_static_pad (parser, "sink");
+ } else {
+ muxer_pad = gst_element_get_compatible_pad (muxer, pad, caps);
+ }
+
+ if (!muxer_pad) {
+ gchar *msg;
+
+ msg = g_strdup_printf ("File with %s type %s is not supported",
+ is_video ? "video" : "audio", mime);
+ g_signal_emit (remuxer, remuxer_signals[SIGNAL_ERROR], 0, msg);
+ g_free (msg);
+ gst_remuxer_cancel (remuxer);
+ return TRUE;
+ } else {
+ if (is_video)
+ remuxer->priv->video_linked = TRUE;
+ else
+ remuxer->priv->audio_linked = TRUE;
+ }
+ queue = gst_element_factory_make ("queue2", NULL);
+ gst_bin_add (GST_BIN(remuxer->priv->main_pipeline), queue);
+ gst_element_set_state (queue, GST_STATE_PLAYING);
+ queue_sink_pad = gst_element_get_static_pad (queue, "sink");
+ queue_src_pad = gst_element_get_static_pad (queue, "src");
+
+ gst_pad_link (pad, queue_sink_pad);
+ gst_pad_link (queue_src_pad, muxer_pad);
+
+ gst_object_unref (muxer);
+ gst_object_unref (queue_sink_pad);
+ gst_object_unref (queue_src_pad);
+
+ gst_caps_unref (caps);
+ return TRUE;
+}
+
+static gboolean
+gst_remuxer_have_type_cb (GstElement *typefind, guint prob,
+ GstCaps *caps, GstRemuxer *remuxer)
+{
+ GstElement *demuxer = NULL;
+ GstElement *parser = NULL;
+ GstStructure *structure;
+ const gchar *mime;
+
+ structure = gst_caps_get_structure (caps, 0);
+ mime = gst_structure_get_name (structure);
+ GST_INFO_OBJECT (remuxer, "Found mime type: %s", mime);
+
+ if (g_strrstr (mime, "video/mpegts")) {
+ GST_INFO_OBJECT (remuxer, "Using tsdemux as demuxer");
+ demuxer = gst_element_factory_make ("tsdemux", NULL);
+ } else if (g_strrstr (mime, "video/x-ms-asf")) {
+ GST_INFO_OBJECT (remuxer, "Using asfdemux as demuxer");
+ demuxer = gst_element_factory_make ("asfdemux", NULL);
+ } else if (g_strrstr (mime, "video/mpeg")) {
+ gboolean sysstream;
+
+ if (gst_structure_get_boolean (structure, "systemstream", &sysstream) &&
+ !sysstream) {
+ GST_INFO_OBJECT (remuxer, "Using mpegvideoparse as demuxer");
+ parser = gst_element_factory_make ("mpegvideoparse", NULL);
+ } else {
+ GST_INFO_OBJECT (remuxer, "Using mpegpsdemux as demuxer");
+ demuxer = gst_element_factory_make ("mpegpsdemux", NULL);
+ }
+ }
+
+ if (demuxer) {
+ gst_bin_add (GST_BIN(remuxer->priv->main_pipeline), demuxer);
+ gst_element_link (typefind, demuxer);
+ g_signal_connect (demuxer, "pad-added",
+ G_CALLBACK (gst_remuxer_pad_added_cb), remuxer);
+ } else if (parser) {
+ GstPad *pad;
+ gst_bin_add (GST_BIN(remuxer->priv->main_pipeline), parser);
+ gst_element_link (typefind, parser);
+ pad = gst_element_get_static_pad (parser, "src");
+ gst_remuxer_pad_added_cb (parser, pad, remuxer);
+ } else {
+ gchar *msg;
+
+ msg = g_strdup_printf ("File with mime type %s is not supported", mime);
+ g_signal_emit (remuxer, remuxer_signals[SIGNAL_ERROR], 0, msg);
+ g_free (msg);
+ gst_remuxer_cancel (remuxer);
+ }
+
+ return TRUE;
+}
+
+static void
+gst_remuxer_initialize (GstRemuxer *remuxer)
+{
+ GstElement *filesrc, *typefind, *muxer, *filesink;
+
+ GST_INFO_OBJECT (remuxer, "Initializing pipeline");
+
+ /* Create elements */
+ remuxer->priv->main_pipeline = gst_pipeline_new ("pipeline");
+
+ filesrc = gst_element_factory_make("filesrc", "source");
+ typefind = gst_element_factory_make("typefind", "typefind");
+ muxer = gst_remuxer_create_video_muxer (remuxer, remuxer->priv->video_muxer_type);
+ filesink = gst_element_factory_make("filesink", "sink");
+
+ /* Set properties */
+ g_object_set (filesrc, "location", remuxer->priv->input_file, NULL);
+ g_object_set (filesink, "location", remuxer->priv->output_file, NULL);
+
+ /* Add elements to the bin */
+ gst_bin_add_many(GST_BIN(remuxer->priv->main_pipeline), filesrc, typefind,
+ muxer, filesink, NULL);
+ gst_element_link(filesrc, typefind);
+ gst_element_link(muxer, filesink);
+
+ g_signal_connect (typefind, "have-type",
+ G_CALLBACK (gst_remuxer_have_type_cb), remuxer);
+}
+
+
+static void
+remuxer_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
+{
+ GstRemuxer *remuxer = (GstRemuxer *) data;
+ GstMessageType msg_type;
+
+ g_return_if_fail (remuxer != NULL);
+ g_return_if_fail (GST_IS_REMUXER (remuxer));
+
+ msg_type = GST_MESSAGE_TYPE (message);
+
+ switch (msg_type) {
+ case GST_MESSAGE_ERROR:
+ {
+ if (remuxer->priv->main_pipeline) {
+ gst_remuxer_cancel (remuxer);
+ }
+ remuxer_error_msg (remuxer, message);
+ break;
+ }
+
+ case GST_MESSAGE_WARNING:
+ {
+ GST_WARNING ("Warning message: %" GST_PTR_FORMAT, message);
+ break;
+ }
+
+ case GST_MESSAGE_EOS:
+ {
+ GST_INFO_OBJECT (remuxer, "EOS message");
+ g_signal_emit (remuxer, remuxer_signals[SIGNAL_PERCENT], 0, (gfloat) 1);
+ break;
+ }
+
+ default:
+ GST_LOG ("Unhandled message: %" GST_PTR_FORMAT, message);
+ break;
+ }
+}
+
+static void
+remuxer_error_msg (GstRemuxer * remuxer, 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 (remuxer, remuxer_signals[SIGNAL_ERROR], 0, err->message);
+ g_error_free (err);
+ }
+ g_free (dbg);
+}
+
+/*******************************************
+ *
+ * Public methods
+ *
+ * ****************************************/
+
+void
+gst_remuxer_start (GstRemuxer * remuxer)
+{
+ g_return_if_fail (remuxer != NULL);
+ g_return_if_fail (GST_IS_REMUXER (remuxer));
+
+ gst_element_set_state (remuxer->priv->main_pipeline, GST_STATE_PLAYING);
+}
+
+void
+gst_remuxer_cancel (GstRemuxer * remuxer)
+{
+ g_return_if_fail (remuxer != NULL);
+ g_return_if_fail (GST_IS_REMUXER (remuxer));
+
+ gst_element_set_state (remuxer->priv->main_pipeline, GST_STATE_NULL);
+ gst_element_get_state (remuxer->priv->main_pipeline, NULL, NULL, -1);
+}
+
+GstRemuxer *
+gst_remuxer_new (gchar * input_file, gchar *output_file, GError ** err)
+{
+ GstRemuxer *remuxer = NULL;
+
+#ifndef GST_DISABLE_GST_INFO
+ if (_remuxer_gst_debug_cat == NULL) {
+ GST_DEBUG_CATEGORY_INIT (_remuxer_gst_debug_cat, "longomatch", 0,
+ "LongoMatch GStreamer Backend");
+ }
+#endif
+
+ remuxer = g_object_new (GST_TYPE_REMUXER, NULL);
+
+ remuxer->priv->input_file = input_file;
+ remuxer->priv->output_file = output_file;
+ remuxer->priv->video_muxer_type = VIDEO_MUXER_MATROSKA;
+
+ gst_remuxer_initialize (remuxer);
+
+ /*Connect bus signals */
+ GST_INFO_OBJECT (remuxer, "Connecting bus signals");
+ remuxer->priv->bus = gst_element_get_bus (remuxer->priv->main_pipeline);
+ gst_bus_add_signal_watch (remuxer->priv->bus);
+ remuxer->priv->sig_bus_async =
+ g_signal_connect (remuxer->priv->bus, "message",
+ G_CALLBACK (remuxer_bus_message_cb), remuxer);
+
+ return remuxer;
+}
diff --git a/libcesarplayer/gst-remuxer.h b/libcesarplayer/gst-remuxer.h
new file mode 100644
index 0000000..e3818bd
--- /dev/null
+++ b/libcesarplayer/gst-remuxer.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Gstreamer DV capturer
+ * Copyright (C) Andoni Morales Alastruey 2008 <ylatuya gmail com>
+ *
+ * Gstreamer DV capturer is free software.
+ *
+ * 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_REMUXER_H_
+#define _GST_REMUXER_H_
+
+#ifdef WIN32
+#define EXPORT __declspec (dllexport)
+#else
+#define EXPORT
+#endif
+
+#include <gst/gst.h>
+#include "common.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_REMUXER (gst_remuxer_get_type ())
+#define GST_REMUXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_REMUXER, GstRemuxer))
+#define GST_REMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_REMUXER, GstRemuxerClass))
+#define GST_IS_REMUXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_REMUXER))
+#define GST_IS_REMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_REMUXER))
+#define GST_REMUXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_REMUXER, GstRemuxerClass))
+#define GCC_ERROR gst_remuxer_error_quark ()
+typedef struct _GstRemuxerClass GstRemuxerClass;
+typedef struct _GstRemuxer GstRemuxer;
+typedef struct GstRemuxerPrivate GstRemuxerPrivate;
+
+
+struct _GstRemuxerClass
+{
+ GObjectClass parent_class;
+
+ void (*percent_completed) (GstRemuxer * remuxer, gfloat *percent);
+ void (*error) (GstRemuxer * remuxer, const char *message);
+};
+
+struct _GstRemuxer
+{
+ GObject parent;
+ GstRemuxerPrivate *priv;
+};
+
+EXPORT GType gst_remuxer_get_type (void) G_GNUC_CONST;
+
+EXPORT void gst_remuxer_init_backend (int *argc, char ***argv);
+EXPORT GstRemuxer *gst_remuxer_new (gchar *in_filename, gchar *out_filename, GError ** err);
+EXPORT void gst_remuxer_start (GstRemuxer * remuxer);
+EXPORT void gst_remuxer_cancel (GstRemuxer * remuxer);
+
+G_END_DECLS
+#endif /* _GST_REMUXER_H_ */
diff --git a/libcesarplayer/src/gst-smart-video-scaler.c b/libcesarplayer/gst-smart-video-scaler.c
similarity index 100%
rename from libcesarplayer/src/gst-smart-video-scaler.c
rename to libcesarplayer/gst-smart-video-scaler.c
diff --git a/libcesarplayer/src/gst-smart-video-scaler.h b/libcesarplayer/gst-smart-video-scaler.h
similarity index 100%
rename from libcesarplayer/src/gst-smart-video-scaler.h
rename to libcesarplayer/gst-smart-video-scaler.h
diff --git a/libcesarplayer/src/gst-video-editor.c b/libcesarplayer/gst-video-editor.c
similarity index 98%
rename from libcesarplayer/src/gst-video-editor.c
rename to libcesarplayer/gst-video-editor.c
index 7dea513..12a9050 100644
--- a/libcesarplayer/src/gst-video-editor.c
+++ b/libcesarplayer/gst-video-editor.c
@@ -29,7 +29,6 @@
#define DEFAULT_VIDEO_ENCODER "vp8enc"
#define DEFAULT_AUDIO_ENCODER "vorbisenc"
#define DEFAULT_VIDEO_MUXER "matroskamux"
-#define FONT_SIZE_FACTOR 0.05
#define LAME_CAPS "audio/x-raw-int, rate=44100, channels=2, endianness=1234, signed=true, width=16, depth=16"
#define VORBIS_CAPS "audio/x-raw-float, rate=44100, channels=2, endianness=1234, signed=true, width=32, depth=32"
#define FAAC_CAPS "audio/x-raw-int, rate=44100, channels=2, endianness=1234, signed=true, width=16, depth=16"
@@ -131,7 +130,7 @@ static void gst_video_editor_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec);
static gboolean gve_query_timeout (GstVideoEditor * gve);
static void gve_apply_new_caps (GstVideoEditor * gve);
-static void gve_apply_title_size (GstVideoEditor * gve);
+static void gve_apply_title_size (GstVideoEditor * gve, gint size);
static void gve_rewrite_headers (GstVideoEditor * gve);
G_DEFINE_TYPE (GstVideoEditor, gst_video_editor, G_TYPE_OBJECT);
@@ -245,7 +244,7 @@ gst_video_editor_class_init (GstVideoEditorClass * klass)
g_object_class_install_property (object_class, PROP_TITLE_SIZE,
g_param_spec_int ("title-size", NULL, NULL,
- 10, 100, 20, G_PARAM_READWRITE));
+ 1, 100, 20, G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_OUTPUT_FILE,
g_param_spec_string ("output_file", NULL, NULL, "", G_PARAM_READWRITE));
@@ -367,7 +366,7 @@ static void
gst_video_editor_set_title_size (GstVideoEditor * gve, gint size)
{
gve->priv->title_size = size;
- gve_apply_title_size (gve);
+ gve_apply_title_size (gve, size);
}
static void
@@ -502,16 +501,35 @@ gve_apply_new_caps (GstVideoEditor * gve)
}
static void
-gve_apply_title_size (GstVideoEditor * gve)
+gve_apply_title_size (GstVideoEditor * gve, gint size)
{
gchar *font;
- font = g_strdup_printf ("sans bold %d", gve->priv->title_size);
- g_object_set (G_OBJECT (gve->priv->textoverlay), "font-desc", font, NULL);
+ font = g_strdup_printf ("sans bold %d", size);
+ g_object_set (G_OBJECT (gve->priv->textoverlay), "font-desc", font,
+ "auto-resize", TRUE, "wrap-mode", 0, NULL);
g_free (font);
}
static void
+gve_set_overlay_title (GstVideoEditor *gve, gchar *title)
+{
+ glong length;
+
+ if (title == NULL)
+ return;
+
+ g_object_set (G_OBJECT (gve->priv->textoverlay), "text", title, NULL);
+
+ length = g_utf8_strlen (title, -1);
+ if (length * gve->priv->title_size > gve->priv->width) {
+ gve_apply_title_size (gve, gve->priv->width / length - 1);
+ } else {
+ gve_apply_title_size (gve, gve->priv->title_size);
+ }
+}
+
+static void
gve_create_video_encode_bin (GstVideoEditor * gve)
{
GstPad *sinkpad = NULL;
@@ -535,8 +553,7 @@ gve_create_video_encode_bin (GstVideoEditor * gve)
g_object_set (G_OBJECT (gve->priv->identity), "single-segment", TRUE, NULL);
g_object_set (G_OBJECT (gve->priv->textoverlay), "font-desc",
- "sans bold 20", "shaded-background", TRUE, "valignment", 2,
- "halignment", 2, NULL);
+ "sans bold 20", "valignment", 2, "halignment", 2, NULL);
g_object_set (G_OBJECT (gve->priv->videoscale), "add-borders", TRUE, NULL);
g_object_set (G_OBJECT (gve->priv->video_encoder), "bitrate",
gve->priv->video_bitrate, NULL);
@@ -818,11 +835,12 @@ gve_query_timeout (GstVideoEditor * gve)
if (gst_element_query_position (gve->priv->video_encoder, &fmt, &pos)) {
if (stop_time - pos <= 0) {
+
gve->priv->active_segment++;
title =
(gchar *) g_list_nth_data (gve->priv->titles,
gve->priv->active_segment);
- g_object_set (G_OBJECT (gve->priv->textoverlay), "text", title, NULL);
+ gve_set_overlay_title (gve, title);
}
}
@@ -870,7 +888,7 @@ gst_video_editor_add_segment (GstVideoEditor * gve, gchar * file,
"start", gve->priv->duration,
"duration", final_duration, "caps", filter, NULL);
if (gve->priv->segments == 0) {
- g_object_set (G_OBJECT (gve->priv->textoverlay), "text", title, NULL);
+ gve_set_overlay_title (gve, title);
}
gst_bin_add (GST_BIN (gve->priv->gnl_video_composition), gnl_filesource);
gve->priv->gnl_video_filesources =
@@ -1066,12 +1084,12 @@ gst_video_editor_set_video_encoder (GstVideoEditor * gve, gchar ** err,
g_object_set (G_OBJECT (encoder), "pass", 17, NULL); //Variable Bitrate-Pass 1
g_object_set (G_OBJECT (encoder), "speed-preset", 4, NULL);//"Faster" preset
break;
- case VIDEO_ENCODER_MPEG4:
+ case VIDEO_ENCODER_XVID:
encoder_name = "xvidenc";
encoder = gst_element_factory_make (encoder_name, encoder_name);
g_object_set (G_OBJECT (encoder), "pass", 1, NULL); //Variable Bitrate-Pass 1
break;
- case VIDEO_ENCODER_XVID:
+ case VIDEO_ENCODER_MPEG4:
encoder_name = "ffenc_mpeg4";
encoder = gst_element_factory_make (encoder_name, encoder_name);
g_object_set (G_OBJECT (encoder), "pass", 512, NULL); //Variable Bitrate-Pass 1
@@ -1303,6 +1321,7 @@ gst_video_editor_set_video_muxer (GstVideoEditor * gve, gchar ** err,
case VIDEO_MUXER_MP4:
muxer_name = "qtmux";
muxer = gst_element_factory_make ("qtmux", muxer_name);
+ g_object_set (muxer, "faststart", TRUE, NULL);
break;
case VIDEO_MUXER_MPEG_PS:
muxer_name = "ffmux_dvd";
diff --git a/libcesarplayer/src/gst-video-editor.h b/libcesarplayer/gst-video-editor.h
similarity index 100%
rename from libcesarplayer/src/gst-video-editor.h
rename to libcesarplayer/gst-video-editor.h
diff --git a/libcesarplayer/src/gstscreenshot.c b/libcesarplayer/gstscreenshot.c
similarity index 98%
rename from libcesarplayer/src/gstscreenshot.c
rename to libcesarplayer/gstscreenshot.c
index f1df208..03f67a8 100644
--- a/libcesarplayer/src/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/src/gstscreenshot.h b/libcesarplayer/gstscreenshot.h
similarity index 100%
rename from libcesarplayer/src/gstscreenshot.h
rename to libcesarplayer/gstscreenshot.h
diff --git a/libcesarplayer/src/gstvideowidget.c b/libcesarplayer/gstvideowidget.c
similarity index 100%
rename from libcesarplayer/src/gstvideowidget.c
rename to libcesarplayer/gstvideowidget.c
diff --git a/libcesarplayer/src/gstvideowidget.h b/libcesarplayer/gstvideowidget.h
similarity index 100%
rename from libcesarplayer/src/gstvideowidget.h
rename to libcesarplayer/gstvideowidget.h
diff --git a/libcesarplayer/src/macros.h b/libcesarplayer/macros.h
similarity index 100%
rename from libcesarplayer/src/macros.h
rename to libcesarplayer/macros.h
diff --git a/libcesarplayer/src/main.c b/libcesarplayer/main.c
similarity index 64%
rename from libcesarplayer/src/main.c
rename to libcesarplayer/main.c
index a2726fc..ff51aab 100644
--- a/libcesarplayer/src/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/test-editor.c b/libcesarplayer/test-editor.c
new file mode 100644
index 0000000..9bfa682
--- /dev/null
+++ b/libcesarplayer/test-editor.c
@@ -0,0 +1,112 @@
+/* -*- 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/>.
+ */
+
+/* Compile with:
+ * gcc -o test-editor test-editor.c gst-video-editor.c `pkg-config --cflags --libs gstreamer-0.10 gtk+-2.0` -DOSTYPE_LINUX -O0 -g
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <gst/gst.h>
+#include "gst-video-editor.h"
+
+static GMainLoop *loop;
+
+static gboolean
+percent_done_cb (GstVideoEditor *remuxer, gfloat percent, GstVideoEditor *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 (GstVideoEditor *remuxer, gchar *error, GstVideoEditor *editor)
+{
+ g_print("ERROR: %s\n", error);
+ g_main_loop_quit (loop);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GstVideoEditor *editor;
+ VideoEncoderType video_encoder;
+ VideoMuxerType video_muxer;
+ AudioEncoderType audio_encoder;
+ gchar *input_file, *output_file;
+ gchar *err = NULL;
+ guint64 start, stop;
+
+ gst_video_editor_init_backend (&argc, &argv);
+
+ if (argc != 6) {
+ g_print("Usage: test-remuxer input_file output_file format start stop\n");
+ return 1;
+ }
+ input_file = argv[1];
+ output_file = argv[2];
+ start = (guint64) g_strtod (argv[3], NULL);
+ stop = (guint64) g_strtod (argv[4], NULL);
+
+ if (!g_strcmp0(argv[3], "mp4")) {
+ video_encoder = VIDEO_ENCODER_H264;
+ video_muxer = VIDEO_MUXER_MP4;
+ audio_encoder = AUDIO_ENCODER_AAC;
+ } else {
+ err = g_strdup_printf ("Invalid format %s\n", argv[3]);
+ goto error;
+ }
+
+ editor = gst_video_editor_new (NULL);
+ gst_video_editor_set_audio_encoder (editor, &err, audio_encoder);
+ if (err != NULL)
+ goto error;
+ gst_video_editor_set_video_encoder (editor, &err, video_encoder);
+ if (err != NULL)
+ goto error;
+ g_object_set (editor, "output_file", output_file,
+ "width", 320, "height", 240, "enable-audio", FALSE,
+ "enable-title", TRUE, "video-bitrate", 1000, "audio-bitrate", 200000,
+ NULL);
+ gst_video_editor_set_video_muxer (editor, &err, video_muxer);
+ if (err != NULL)
+ goto error;
+ gst_video_editor_add_segment (editor, input_file, start, stop,
+ (gdouble) 1, "Test", TRUE);
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_signal_connect (editor, "error", G_CALLBACK (error_cb), editor);
+ g_signal_connect (editor, "percent_completed", G_CALLBACK(percent_done_cb),
+ editor);
+ gst_video_editor_start (editor);
+ g_main_loop_run (loop);
+
+ return 0;
+
+error:
+ g_print ("ERROR: %s", err);
+ return 1;
+
+}
+
diff --git a/libcesarplayer/test-remuxer.c b/libcesarplayer/test-remuxer.c
new file mode 100644
index 0000000..02a18bf
--- /dev/null
+++ b/libcesarplayer/test-remuxer.c
@@ -0,0 +1,71 @@
+/* -*- 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/>.
+ */
+
+/* Compile with:
+ * gcc -o test-remuxer test-remuxer.c gst-remuxer.c `pkg-config --cflags --libs gstreamer-0.10` -DOSTYPE_LINUX -O0 -g
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "gst-remuxer.h"
+
+static gboolean
+percent_done_cb (GstRemuxer *remuxer, gfloat percent, GMainLoop *loop)
+{
+ if (percent == 1) {
+ g_print("SUCESS!\n");
+ g_main_loop_quit (loop);
+ } else {
+ g_print("----> %f%%", percent);
+ }
+}
+
+static gboolean
+error_cb (GstRemuxer *remuxer, gchar *error, GMainLoop *loop)
+{
+ g_print("ERROR: %s\n", error);
+ g_main_loop_quit (loop);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GstRemuxer *remuxer;
+ GMainLoop *loop;
+
+ gst_remuxer_init_backend (&argc, &argv);
+
+ if (argc != 3) {
+ g_print("Usage: test-remuxer input_file output_file\n");
+ return 1;
+ }
+ remuxer = gst_remuxer_new (argv[1], argv[2], NULL);
+ gst_remuxer_start (remuxer);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ g_signal_connect (remuxer, "percent_completed",
+ G_CALLBACK (percent_done_cb), loop);
+ g_signal_connect (remuxer, "error",
+ G_CALLBACK (error_cb), loop);
+
+ g_main_loop_run (loop);
+
+ return 0;
+}
diff --git a/libcesarplayer/src/video-utils.c b/libcesarplayer/video-utils.c
similarity index 79%
rename from libcesarplayer/src/video-utils.c
rename to libcesarplayer/video-utils.c
index d6fc907..6dab75d 100644
--- a/libcesarplayer/src/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"
@@ -235,8 +262,8 @@ totem_ratio_fits_screen (GdkWindow * video_window, int video_width,
return TRUE;
}
-void
-gst_set_window_handle(GstXOverlay *xoverlay, GdkWindow *window)
+guintptr
+gst_get_window_handle(GdkWindow *window)
{
guintptr window_handle;
@@ -248,6 +275,13 @@ gst_set_window_handle(GstXOverlay *xoverlay, GdkWindow *window)
#elif defined (GDK_WINDOWING_X11)
window_handle = GDK_WINDOW_XID (window);
#endif
+
+ return window_handle;
+}
+
+void
+gst_set_window_handle(GstXOverlay *xoverlay, guintptr window_handle)
+{
gst_x_overlay_set_window_handle (xoverlay, window_handle);
}
diff --git a/libcesarplayer/video-utils.h b/libcesarplayer/video-utils.h
new file mode 100644
index 0000000..4fd9704
--- /dev/null
+++ b/libcesarplayer/video-utils.h
@@ -0,0 +1,70 @@
+/*
+ * 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>
+#include <gdk/gdk.h>
+#if defined (GDK_WINDOWING_X11)
+#include <gdk/gdkx.h>
+#elif defined (GDK_WINDOWING_WIN32)
+#include <gdk/gdkwin32.h>
+#elif defined (GDK_WINDOWING_QUARTZ)
+#include <gdk/gdkquartz.h>
+#endif
+#include <gtk/gtk.h>
+
+
+#ifdef WIN32
+#define EXPORT __declspec (dllexport)
+#else
+#define EXPORT
+#endif
+
+#define TOTEM_OBJECT_HAS_SIGNAL(obj, name) (g_signal_lookup (name, g_type_from_name (G_OBJECT_TYPE_NAME (obj))) != 0)
+
+void totem_gdk_window_set_invisible_cursor (GdkWindow * window);
+void totem_gdk_window_set_waiting_cursor (GdkWindow * window);
+
+gboolean totem_display_is_local (void);
+
+char *totem_time_to_string (gint64 msecs);
+gint64 totem_string_to_time (const char *time_string);
+char *totem_time_to_string_text (gint64 msecs);
+
+void totem_widget_set_preferred_size (GtkWidget * widget, gint width,
+ gint height);
+gboolean totem_ratio_fits_screen (GdkWindow * window, int video_width,
+ int video_height, gfloat ratio);
+
+void init_backend (int argc, char **argv);
+guintptr gst_get_window_handle (GdkWindow *window);
+void gst_set_window_handle (GstXOverlay *overlay, guintptr window_handle);
+void init_debug();
+
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]