1
0
Fork 0

2006-08-30 Jorn Baayen <jorn@openedhand.com>

* README:
	* clutter/Makefile.am:
	* clutter/clutter-audio.c:
	* clutter/clutter-audio.h:
	* clutter/clutter-main.c: (clutter_init):
	* clutter/clutter-media.c:
	* clutter/clutter-media.h:
	* clutter/clutter-video-texture.c:
	* clutter/clutter-video-texture.h:
	* clutter/clutter.h:
	* configure.ac:
	* examples/Makefile.am:
	* examples/README:
	* examples/video-cube.c:
	* examples/video-player.c:
	* gst/Makefile.am:
	* gst/clutterimagesink.:
	* gst/clutterimagesink.c:
	* gst/clutterimagesink.h:
	* gtk/Makefile.am:

	Remove gstreamer bits. There live in clutter-gst now.
This commit is contained in:
Jorn Baayen 2006-08-30 13:48:48 +00:00
parent f907bcee1e
commit 458b4b47a7
26 changed files with 42 additions and 5366 deletions

View file

@ -1,3 +1,28 @@
2006-08-30 Jorn Baayen <jorn@openedhand.com>
* README:
* clutter/Makefile.am:
* clutter/clutter-audio.c:
* clutter/clutter-audio.h:
* clutter/clutter-main.c: (clutter_init):
* clutter/clutter-media.c:
* clutter/clutter-media.h:
* clutter/clutter-video-texture.c:
* clutter/clutter-video-texture.h:
* clutter/clutter.h:
* configure.ac:
* examples/Makefile.am:
* examples/README:
* examples/video-cube.c:
* examples/video-player.c:
* gst/Makefile.am:
* gst/clutterimagesink.:
* gst/clutterimagesink.c:
* gst/clutterimagesink.h:
* gtk/Makefile.am:
Remove gstreamer bits. There live in clutter-gst now.
2006-08-30 Jorn Baayen <jorn@openedhand.com>
* clutter/Makefile.am:

6
README
View file

@ -12,9 +12,9 @@ It currently uses fairly low end GL functionality with an aim to still
work well on open source graphics drivers as well as possibly making
an eventual GL ES port feasable.
Clutter currently requires GLib >= 2.8, GdkPixbuf, Gstreamer 0.10 and
OpenGL >= 1.2. Its also recommended you have some kind of working
hardware OpenGL on your target system.
Clutter currently requires GLib >= 2.8, GdkPixbuf and OpenGL >= 1.2.
Its also recommended you have some kind of working hardware OpenGL on
your target system.
Clutter is LGPL licensed.

View file

@ -9,7 +9,6 @@ source_h = \
$(srcdir)/clutter-keysyms.h \
$(srcdir)/clutter-util.h \
$(srcdir)/clutter-fixed.h \
$(srcdir)/clutter-media.h \
$(srcdir)/clutter-event.h \
$(srcdir)/clutter-color.h \
$(srcdir)/clutter-feature.h \
@ -20,12 +19,10 @@ source_h = \
$(srcdir)/clutter-rectangle.h \
$(srcdir)/clutter-texture.h \
$(srcdir)/clutter-clone-texture.h \
$(srcdir)/clutter-video-texture.h \
$(srcdir)/clutter-label.h \
$(srcdir)/clutter-behaviour.h \
$(srcdir)/clutter-behaviours.h \
$(srcdir)/clutter-alpha.h \
$(srcdir)/clutter-audio.h \
$(srcdir)/clutter-main.h
clutter-marshal.h: clutter-marshal.list
@ -76,7 +73,6 @@ CLEANFILES = $(BUILT_SOURCES) stamp-clutter-enum-types.h
source_c = clutter-main.c \
clutter-util.c \
clutter-feature.c \
clutter-media.c \
clutter-event.c \
clutter-color.c \
clutter-timeline.c \
@ -85,13 +81,11 @@ source_c = clutter-main.c \
clutter-rectangle.c \
clutter-texture.c \
clutter-clone-texture.c \
clutter-video-texture.c \
clutter-label.c \
clutter-actor.c \
clutter-behaviour.c \
clutter-behaviours.c \
clutter-alpha.c \
clutter-audio.c \
clutter-enum-types.c
source_h_priv = clutter-private.h
@ -101,11 +95,11 @@ libclutter_@CLUTTER_MAJORMINOR@_la_SOURCES = $(MARSHALFILES) \
$(source_h) \
$(source_h_priv)
INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ $(GST_CFLAGS) -I$(top_srcdir)
INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ -I$(top_srcdir)
lib_LTLIBRARIES = libclutter-@CLUTTER_MAJORMINOR@.la
libclutter_@CLUTTER_MAJORMINOR@_la_LIBADD = @CLUTTER_LIBS@ $(GST_LIBS)
libclutter_@CLUTTER_MAJORMINOR@_la_LIBADD = @CLUTTER_LIBS@
libclutter_@CLUTTER_MAJORMINOR@_la_LDFLAGS = @CLUTTER_LT_LDFLAGS@
clutterheadersdir = $(includedir)/clutter-@CLUTTER_MAJORMINOR@/clutter

View file

@ -1,818 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
* Jorn Baayen <jorn@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:clutter-audio
* @short_description: Object for playback of audio files.
*
* #ClutterAudio is an object that plays audio files.
*/
#include "clutter-audio.h"
#include "clutter-main.h"
#include "clutter-private.h" /* for DBG */
#include "clutter-marshal.h"
#include <gst/gst.h>
#include <gst/audio/gstbaseaudiosink.h>
#include <glib.h>
struct _ClutterAudioPrivate
{
GstElement *playbin;
char *uri;
gboolean can_seek;
int buffer_percent;
int duration;
guint tick_timeout_id;
};
enum {
PROP_0,
/* ClutterMedia proprs */
PROP_URI,
PROP_PLAYING,
PROP_POSITION,
PROP_VOLUME,
PROP_CAN_SEEK,
PROP_BUFFER_PERCENT,
PROP_DURATION
};
#define TICK_TIMEOUT 0.5
static void clutter_media_init (ClutterMediaInterface *iface);
static gboolean tick_timeout (ClutterAudio *audio);
G_DEFINE_TYPE_EXTENDED (ClutterAudio, \
clutter_audio, \
G_TYPE_OBJECT, \
0, \
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MEDIA, \
clutter_media_init));
/* Interface implementation */
static void
set_uri (ClutterMedia *media,
const char *uri)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
GstState state, pending;
g_return_if_fail (CLUTTER_IS_AUDIO (audio));
priv = audio->priv;
if (!priv->playbin)
return;
g_free (priv->uri);
if (uri)
{
priv->uri = g_strdup (uri);
/**
* Ensure the tick timeout is installed.
*
* We also have it installed in PAUSED state, because
* seeks etc may have a delayed effect on the position.
**/
if (priv->tick_timeout_id == 0)
{
priv->tick_timeout_id = g_timeout_add (TICK_TIMEOUT * 1000,
(GSourceFunc) tick_timeout,
audio);
}
}
else
{
priv->uri = NULL;
if (priv->tick_timeout_id > 0)
{
g_source_remove (priv->tick_timeout_id);
priv->tick_timeout_id = 0;
}
}
priv->can_seek = FALSE;
priv->duration = 0;
gst_element_get_state (priv->playbin, &state, &pending, 0);
if (pending)
state = pending;
gst_element_set_state (priv->playbin, GST_STATE_NULL);
g_object_set (priv->playbin,
"uri", uri,
NULL);
/**
* Restore state.
**/
if (uri)
gst_element_set_state (priv->playbin, state);
/*
* Emit notififications for all these to make sure UI is not showing
* any properties of the old URI.
*/
g_object_notify (G_OBJECT (audio), "uri");
g_object_notify (G_OBJECT (audio), "can-seek");
g_object_notify (G_OBJECT (audio), "duration");
g_object_notify (G_OBJECT (audio), "position");
}
static const char *
get_uri (ClutterMedia *media)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_AUDIO (audio), NULL);
priv = audio->priv;
return priv->uri;
}
static void
set_playing (ClutterMedia *media,
gboolean playing)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
g_return_if_fail (CLUTTER_IS_AUDIO (audio));
priv = audio->priv;
if (!priv->playbin)
return;
if (priv->uri)
{
GstState state;
if (playing)
state = GST_STATE_PLAYING;
else
state = GST_STATE_PAUSED;
gst_element_set_state (audio->priv->playbin, state);
}
else
{
if (playing)
g_warning ("Tried to play, but no URI is loaded.");
}
g_object_notify (G_OBJECT (audio), "playing");
g_object_notify (G_OBJECT (audio), "position");
}
static gboolean
get_playing (ClutterMedia *media)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
GstState state, pending;
g_return_val_if_fail (CLUTTER_IS_AUDIO (audio), FALSE);
priv = audio->priv;
if (!priv->playbin)
return FALSE;
gst_element_get_state (priv->playbin, &state, &pending, 0);
if (pending)
return (pending == GST_STATE_PLAYING);
else
return (state == GST_STATE_PLAYING);
}
static void
set_position (ClutterMedia *media,
int position) /* seconds */
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
GstState state, pending;
g_return_if_fail (CLUTTER_IS_AUDIO (audio));
priv = audio->priv;
if (!priv->playbin)
return;
gst_element_get_state (priv->playbin, &state, &pending, 0);
if (pending)
state = pending;
gst_element_set_state (priv->playbin, GST_STATE_PAUSED);
gst_element_seek (priv->playbin,
1.0,
GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET,
position * GST_SECOND,
0, 0);
gst_element_set_state (priv->playbin, state);
}
static int
get_position (ClutterMedia *media)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
GstQuery *query;
gint64 position;
g_return_val_if_fail (CLUTTER_IS_AUDIO (audio), -1);
priv = audio->priv;
if (!priv->playbin)
return -1;
query = gst_query_new_position (GST_FORMAT_TIME);
if (gst_element_query (priv->playbin, query))
gst_query_parse_position (query, NULL, &position);
else
position = 0;
gst_query_unref (query);
return (position / GST_SECOND);
}
static void
set_volume (ClutterMedia *media,
double volume)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
g_return_if_fail (CLUTTER_IS_AUDIO (audio));
// g_return_if_fail (volume >= 0.0 && volume <= GST_VOL_MAX);
priv = audio->priv;
if (!priv->playbin)
return;
g_object_set (G_OBJECT (audio->priv->playbin),
"volume", volume,
NULL);
g_object_notify (G_OBJECT (audio), "volume");
}
static double
get_volume (ClutterMedia *media)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
ClutterAudioPrivate *priv;
double volume;
g_return_val_if_fail (CLUTTER_IS_AUDIO (audio), 0.0);
priv = audio->priv;
if (!priv->playbin)
return 0.0;
g_object_get (priv->playbin,
"volume", &volume,
NULL);
return volume;
}
static gboolean
can_seek (ClutterMedia *media)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
g_return_val_if_fail (CLUTTER_IS_AUDIO (audio), FALSE);
return audio->priv->can_seek;
}
static int
get_buffer_percent (ClutterMedia *media)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
g_return_val_if_fail (CLUTTER_IS_AUDIO (audio), -1);
return audio->priv->buffer_percent;
}
static int
get_duration (ClutterMedia *media)
{
ClutterAudio *audio = CLUTTER_AUDIO(media);
g_return_val_if_fail (CLUTTER_IS_AUDIO (audio), -1);
return audio->priv->duration;
}
static void
clutter_media_init (ClutterMediaInterface *iface)
{
iface->set_uri = set_uri;
iface->get_uri = get_uri;
iface->set_playing = set_playing;
iface->get_playing = get_playing;
iface->set_position = set_position;
iface->get_position = get_position;
iface->set_volume = set_volume;
iface->get_volume = get_volume;
iface->can_seek = can_seek;
iface->get_buffer_percent = get_buffer_percent;
iface->get_duration = get_duration;
}
static void
clutter_audio_dispose (GObject *object)
{
ClutterAudio *self;
ClutterAudioPrivate *priv;
self = CLUTTER_AUDIO(object);
priv = self->priv;
/* FIXME: flush an errors off bus ? */
/* gst_bus_set_flushing (priv->bus, TRUE); */
if (priv->playbin)
{
gst_element_set_state (priv->playbin, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (priv->playbin));
priv->playbin = NULL;
}
if (priv->tick_timeout_id > 0)
{
g_source_remove (priv->tick_timeout_id);
priv->tick_timeout_id = 0;
}
G_OBJECT_CLASS (clutter_audio_parent_class)->dispose (object);
}
static void
clutter_audio_finalize (GObject *object)
{
ClutterAudio *self;
ClutterAudioPrivate *priv;
self = CLUTTER_AUDIO(object);
priv = self->priv;
if (priv->uri)
g_free(priv->uri);
G_OBJECT_CLASS (clutter_audio_parent_class)->finalize (object);
}
static void
clutter_audio_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterAudio *audio;
audio = CLUTTER_AUDIO(object);
switch (property_id)
{
case PROP_URI:
clutter_media_set_uri (CLUTTER_MEDIA(audio),
g_value_get_string (value));
break;
case PROP_PLAYING:
clutter_media_set_playing (CLUTTER_MEDIA(audio),
g_value_get_boolean (value));
break;
case PROP_POSITION:
clutter_media_set_position (CLUTTER_MEDIA(audio),
g_value_get_int (value));
break;
case PROP_VOLUME:
clutter_media_set_volume (CLUTTER_MEDIA(audio),
g_value_get_double (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
clutter_audio_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
ClutterAudio *audio;
ClutterMedia *media;
audio = CLUTTER_AUDIO (object);
media = CLUTTER_MEDIA (audio);
switch (property_id)
{
case PROP_URI:
g_value_set_string (value, clutter_media_get_uri (media));
break;
case PROP_PLAYING:
g_value_set_boolean (value, clutter_media_get_playing (media));
break;
case PROP_POSITION:
g_value_set_int (value, clutter_media_get_position (media));
break;
case PROP_VOLUME:
g_value_set_double (value, clutter_media_get_volume (media));
break;
case PROP_CAN_SEEK:
g_value_set_boolean (value, clutter_media_get_can_seek (media));
break;
case PROP_BUFFER_PERCENT:
g_value_set_int (value, clutter_media_get_buffer_percent (media));
break;
case PROP_DURATION:
g_value_set_int (value, clutter_media_get_duration (media));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
clutter_audio_class_init (ClutterAudioClass *klass)
{
GObjectClass *object_class;
object_class = (GObjectClass*)klass;
object_class->dispose = clutter_audio_dispose;
object_class->finalize = clutter_audio_finalize;
object_class->set_property = clutter_audio_set_property;
object_class->get_property = clutter_audio_get_property;
/* Interface props */
g_object_class_override_property (object_class, PROP_URI, "uri");
g_object_class_override_property (object_class, PROP_PLAYING, "playing");
g_object_class_override_property (object_class, PROP_POSITION, "position");
g_object_class_override_property (object_class, PROP_VOLUME, "volume");
g_object_class_override_property (object_class, PROP_CAN_SEEK, "can-seek");
g_object_class_override_property (object_class, PROP_DURATION, "duration");
g_object_class_override_property (object_class, PROP_BUFFER_PERCENT,
"buffer-percent" );
}
static void
bus_message_error_cb (GstBus *bus,
GstMessage *message,
ClutterAudio *audio)
{
GError *error;
error = NULL;
gst_message_parse_error (message, &error, NULL);
g_signal_emit_by_name (CLUTTER_MEDIA(audio), "error", error);
g_error_free (error);
}
static void
bus_message_eos_cb (GstBus *bus,
GstMessage *message,
ClutterAudio *audio)
{
g_object_notify (G_OBJECT (audio), "position");
g_signal_emit_by_name (CLUTTER_MEDIA(audio), "eos");
}
static void
bus_message_tag_cb (GstBus *bus,
GstMessage *message,
ClutterAudio *audio)
{
GstTagList *tag_list;
gst_message_parse_tag (message, &tag_list);
g_signal_emit_by_name (CLUTTER_MEDIA(audio),
"metadata-available",
tag_list);
gst_tag_list_free (tag_list);
}
static void
bus_message_buffering_cb (GstBus *bus,
GstMessage *message,
ClutterAudio *audio)
{
const GstStructure *str;
str = gst_message_get_structure (message);
if (!str)
return;
if (!gst_structure_get_int (str,
"buffer-percent",
&audio->priv->buffer_percent))
return;
g_object_notify (G_OBJECT (audio), "buffer-percent");
}
static void
bus_message_duration_cb (GstBus *bus,
GstMessage *message,
ClutterAudio *audio)
{
GstFormat format;
gint64 duration;
gst_message_parse_duration (message,
&format,
&duration);
if (format != GST_FORMAT_TIME)
return;
audio->priv->duration = duration / GST_SECOND;
g_object_notify (G_OBJECT (audio), "duration");
}
static void
bus_message_state_change_cb (GstBus *bus,
GstMessage *message,
ClutterAudio *audio)
{
gpointer src;
GstState old_state, new_state;
src = GST_MESSAGE_SRC (message);
if (src != audio->priv->playbin)
return;
gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
if (old_state == GST_STATE_READY &&
new_state == GST_STATE_PAUSED)
{
GstQuery *query;
/**
* Determine whether we can seek.
**/
query = gst_query_new_seeking (GST_FORMAT_TIME);
if (gst_element_query (audio->priv->playbin, query)) {
gst_query_parse_seeking (query,
NULL,
&audio->priv->can_seek,
NULL,
NULL);
} else {
/*
* Could not query for ability to seek. Determine
* using URI.
*/
if (g_str_has_prefix (audio->priv->uri,
"http://")) {
audio->priv->can_seek = FALSE;
} else {
audio->priv->can_seek = TRUE;
}
}
gst_query_unref (query);
g_object_notify (G_OBJECT (audio), "can-seek");
/**
* Determine the duration.
**/
query = gst_query_new_duration (GST_FORMAT_TIME);
if (gst_element_query (audio->priv->playbin, query))
{
gint64 duration;
gst_query_parse_duration (query, NULL, &duration);
audio->priv->duration = duration / GST_SECOND;
g_object_notify (G_OBJECT (audio), "duration");
}
gst_query_unref (query);
}
}
static gboolean
tick_timeout (ClutterAudio *audio)
{
g_object_notify (G_OBJECT (audio), "position");
return TRUE;
}
static void
fakesink_handoff_cb (GstElement *fakesrc,
GstBuffer *buffer,
GstPad *pad,
gpointer user_data)
{
GstStructure *structure;
int width, height;
GdkPixbuf *pixb;
structure = gst_caps_get_structure(GST_CAPS(buffer->caps), 0);
gst_structure_get_int(structure, "width", &width);
gst_structure_get_int(structure, "height", &height);
/* FIXME: We really dont want to do this every time as gobject creation
* really need a clutter_texture_set_from_data call ?
*/
pixb = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
GDK_COLORSPACE_RGB,
FALSE,
8,
width,
height,
(3 * width + 3) &~ 3,
NULL,
NULL);
if (pixb)
{
clutter_texture_set_pixbuf (CLUTTER_TEXTURE(user_data), pixb);
g_object_unref(G_OBJECT(pixb));
}
}
static gboolean
lay_pipeline (ClutterAudio *audio)
{
ClutterAudioPrivate *priv;
GstElement *audio_sink = NULL;
priv = audio->priv;
priv->playbin = gst_element_factory_make ("playbin", "playbin");
if (!priv->playbin)
{
g_warning ("Unable to create playbin GST element.");
return FALSE;
}
audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
if (!audio_sink)
{
audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
if (!audio_sink)
{
audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
g_warning ("Could not create a GST audio_sink. "
"Audio unavailable.");
if (!audio_sink) /* Need to bother ? */
audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
}
}
g_object_set (G_OBJECT (priv->playbin),
"audio-sink", audio_sink,
NULL);
return TRUE;
}
static void
clutter_audio_init (ClutterAudio *audio)
{
ClutterAudioPrivate *priv;
GstBus *bus;
priv = g_new0 (ClutterAudioPrivate, 1);
audio->priv = priv;
if (!lay_pipeline(audio))
{
g_warning("Failed to initiate suitable playback pipeline.");
return;
}
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->playbin));
gst_bus_add_signal_watch (bus);
g_signal_connect_object (bus,
"message::error",
G_CALLBACK (bus_message_error_cb),
audio,
0);
g_signal_connect_object (bus,
"message::eos",
G_CALLBACK (bus_message_eos_cb),
audio,
0);
g_signal_connect_object (bus,
"message::tag",
G_CALLBACK (bus_message_tag_cb),
audio,
0);
g_signal_connect_object (bus,
"message::buffering",
G_CALLBACK (bus_message_buffering_cb),
audio,
0);
g_signal_connect_object (bus,
"message::duration",
G_CALLBACK (bus_message_duration_cb),
audio,
0);
g_signal_connect_object (bus,
"message::state-changed",
G_CALLBACK (bus_message_state_change_cb),
audio,
0);
gst_object_unref (GST_OBJECT (bus));
return;
}
/**
* clutter_audio_new:
*
* Creates #ClutterAudio object.
*
* Return value: A newly allocated #ClutterAudio object.
*/
ClutterAudio*
clutter_audio_new (void)
{
return g_object_new (CLUTTER_TYPE_AUDIO, NULL);
}

View file

@ -1,87 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
* Jorn Baayen <jorn@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _HAVE_CLUTTER_AUDIO_H
#define _HAVE_CLUTTER_AUDIO_H
#include <glib-object.h>
#include <clutter/clutter-media.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_AUDIO clutter_audio_get_type()
#define CLUTTER_AUDIO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
CLUTTER_TYPE_AUDIO, ClutterAudio))
#define CLUTTER_AUDIO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
CLUTTER_TYPE_AUDIO, ClutterAudioClass))
#define CLUTTER_IS_AUDIO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
CLUTTER_TYPE_AUDIO))
#define CLUTTER_IS_AUDIO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
CLUTTER_TYPE_AUDIO))
#define CLUTTER_AUDIO_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
CLUTTER_TYPE_AUDIO, ClutterAudioClass))
typedef struct _ClutterAudio ClutterAudio;
typedef struct _ClutterAudioClass ClutterAudioClass;
typedef struct _ClutterAudioPrivate ClutterAudioPrivate;
/* #define CLUTTER_AUDIO_ERROR clutter_audio_error_quark() */
struct _ClutterAudio
{
GObject parent;
ClutterAudioPrivate *priv;
};
struct _ClutterAudioClass
{
GObjectClass parent_class;
/* Future padding */
void (* _clutter_reserved1) (void);
void (* _clutter_reserved2) (void);
void (* _clutter_reserved3) (void);
void (* _clutter_reserved4) (void);
void (* _clutter_reserved5) (void);
void (* _clutter_reserved6) (void);
};
GType clutter_audio_get_type (void) G_GNUC_CONST;
ClutterAudio *clutter_audio_new (void);
G_END_DECLS
#endif

View file

@ -41,8 +41,6 @@
#include "clutter-stage.h"
#include "clutter-private.h"
#include <gst/gst.h> /* for gst_init() */
typedef struct
{
GSource source;
@ -551,8 +549,6 @@ clutter_init (int *argc, char ***argv)
XInitThreads();
gst_init (argc, argv);
context->main_loops = NULL;
context->main_loop_level = 0;

View file

@ -1,380 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:clutter-media
* @short_description: An interface for controlling playback of media data.
*
* #ClutterMedia is an interface for controlling playback of media data.
*/
#include "config.h"
#include "clutter-media.h"
#include "clutter-main.h"
#include "clutter-enum-types.h"
#include "clutter-private.h" /* for DBG */
static void clutter_media_base_init (gpointer g_class);
GType
clutter_media_get_type (void)
{
static GType media_type = 0;
if (!media_type)
{
static const GTypeInfo media_info =
{
sizeof (ClutterMediaInterface),
clutter_media_base_init,
NULL,
};
media_type = g_type_register_static (G_TYPE_INTERFACE, "ClutterMedia",
&media_info, 0);
}
return media_type;
}
static void
clutter_media_base_init (gpointer g_iface)
{
static gboolean initialized = FALSE;
if (!initialized)
{
initialized = TRUE;
/* props */
g_object_interface_install_property
(g_iface,
g_param_spec_string
("uri",
"URI",
"The loaded URI.",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_interface_install_property
(g_iface,
g_param_spec_boolean
("playing",
"Playing",
"TRUE if playing.",
FALSE,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_interface_install_property
(g_iface,
g_param_spec_int
("position",
"Position",
"The position in the current stream in seconds.",
0, G_MAXINT, 0,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_interface_install_property
(g_iface,
g_param_spec_double
("volume",
"Volume",
"The audio volume.",
0, 100, 50,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_interface_install_property
(g_iface,
g_param_spec_boolean
("can-seek",
"Can seek",
"TRUE if the current stream is seekable.",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_interface_install_property
(g_iface,
g_param_spec_int
("buffer-percent",
"Buffer percent",
"The percentage the current stream buffer is filled.",
0, 100, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_interface_install_property
(g_iface,
g_param_spec_int
("duration",
"Duration",
"The duration of the current stream in seconds.",
0, G_MAXINT, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
/* signals */
g_signal_new ("metadata-available",
CLUTTER_TYPE_MEDIA,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterMediaInterface,
metadata_available),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
g_signal_new ("eos",
CLUTTER_TYPE_MEDIA,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterMediaInterface,
eos),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_signal_new ("error",
CLUTTER_TYPE_MEDIA,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterMediaInterface,
error),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
}
}
/**
* clutter_media_set_uri:
* @media: #ClutterMedia object
* @uri: Uri
*
* Sets the uri of @media to @uri.
*/
void
clutter_media_set_uri (ClutterMedia *media,
const char *uri)
{
g_return_if_fail (CLUTTER_IS_MEDIA(media));
CLUTTER_MEDIA_GET_INTERFACE (media)->set_uri (media, uri);
}
/**
* clutter_media_get_uri:
* @media: A #ClutterMedia object
*
* Retrieves the URI from @media.
*
* Return value: The URI as a string.
*/
const char*
clutter_media_get_uri (ClutterMedia *media)
{
g_return_val_if_fail (CLUTTER_IS_MEDIA(media), NULL);
return CLUTTER_MEDIA_GET_INTERFACE (media)->get_uri (media);
}
/**
* clutter_media_set_playing:
* @media: A #ClutterMedia object
* @playing: TRUE to start playing, FALSE to stop.
*
* Starts or stops @media playing.
*/
void
clutter_media_set_playing (ClutterMedia *media,
gboolean playing)
{
g_return_if_fail (CLUTTER_IS_MEDIA(media));
CLUTTER_MEDIA_GET_INTERFACE (media)->set_playing (media, playing);
}
/**
* clutter_media_get_playing:
* @media: A #ClutterMedia object
*
* Retrieves the state of @media.
*
* Return value: TRUE if playing, FALSE if stopped.
*/
gboolean
clutter_media_get_playing (ClutterMedia *media)
{
g_return_val_if_fail (CLUTTER_IS_MEDIA(media), FALSE);
return CLUTTER_MEDIA_GET_INTERFACE (media)->get_playing (media);
}
/**
* clutter_media_set_position:
* @media: A #ClutterMedia object
* @position: The desired position.
*
* Sets the playback position of @media to @position.
*/
void
clutter_media_set_position (ClutterMedia *media,
int position)
{
g_return_if_fail (CLUTTER_IS_MEDIA(media));
CLUTTER_MEDIA_GET_INTERFACE (media)->set_position (media, position);
}
/**
* clutter_media_get_position:
* @media: A #ClutterMedia object
*
* Retrieves the position of @media.
*
* Return value: The playback position.
*/
int
clutter_media_get_position (ClutterMedia *media)
{
g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0);
return CLUTTER_MEDIA_GET_INTERFACE (media)->get_position (media);
}
/**
* clutter_media_set_volume:
* @media: A #ClutterMedia object
* @volume: The volume as a double between 0.0 and 1.0
*
* Sets the playback volume of @media to @volume.
*/
void
clutter_media_set_volume (ClutterMedia *media,
double volume)
{
g_return_if_fail (CLUTTER_IS_MEDIA(media));
CLUTTER_MEDIA_GET_INTERFACE (media)->set_volume (media, volume);
}
/**
* clutter_media_get_volume:
* @media: A #ClutterMedia object
*
* Retrieves the playback volume of @media.
*
* Return value: The playback volume between 0.0 and 1.0
*/
double
clutter_media_get_volume (ClutterMedia *media)
{
g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0.0);
return CLUTTER_MEDIA_GET_INTERFACE (media)->get_volume (media);
}
/**
* clutter_media_get_can_seek:
* @media: A #ClutterMedia object
*
* Retrieves whether @media is seekable or not.
*
* Return value: TRUE if @media can seek, FALSE otherwise.
*/
gboolean
clutter_media_get_can_seek (ClutterMedia *media)
{
g_return_val_if_fail (CLUTTER_IS_MEDIA(media), FALSE);
return CLUTTER_MEDIA_GET_INTERFACE (media)->can_seek (media);
}
/**
* clutter_media_get_buffer_percent:
* @media: A #ClutterMedia object
*
* Retrieves the amount of the stream that is buffered.
*
* Return value: percentage value
*/
int
clutter_media_get_buffer_percent (ClutterMedia *media)
{
g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0);
return CLUTTER_MEDIA_GET_INTERFACE (media)->get_buffer_percent (media);
}
/**
* clutter_media_get_duration:
* @media: A #ClutterMedia object
*
* Retrieves the duration of the media stream that @media represents.
*
* Return value: The length of the media stream.
*/
int
clutter_media_get_duration (ClutterMedia *media)
{
g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0);
return CLUTTER_MEDIA_GET_INTERFACE (media)->get_duration (media);
}
/* helper funcs */
/**
* clutter_media_set_filename:
* @media: A #ClutterMedia object
* @filename: A filename to media file.
*
* Converts a filesystem path to a uri and calls clutter_media_set_uri
*/
void
clutter_media_set_filename (ClutterMedia *media, const gchar *filename)
{
gchar *uri;
if (filename[0] != '/')
uri = g_strdup_printf ("file://%s/%s", g_get_current_dir (), filename);
else
uri = g_strdup_printf ("file://%s", filename);
clutter_media_set_uri (media, uri);
g_free(uri);
}

View file

@ -1,124 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _HAVE_CLUTTER_MEDIA_H
#define _HAVE_CLUTTER_MEDIA_H
#include <glib-object.h>
#include <gst/gsttaglist.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_MEDIA clutter_media_get_type()
#define CLUTTER_MEDIA(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
CLUTTER_TYPE_MEDIA, ClutterMedia))
#define CLUTTER_IS_MEDIA(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
CLUTTER_TYPE_MEDIA))
#define CLUTTER_MEDIA_GET_INTERFACE(obj) \
(G_TYPE_INSTANCE_GET_INTERFACE ((obj), \
CLUTTER_TYPE_MEDIA, ClutterMediaInterface))
typedef struct _ClutterMedia ClutterMedia;
typedef struct _ClutterMediaInterface ClutterMediaInterface;
struct _ClutterMediaInterface
{
GTypeInterface base_iface;
void (*set_uri) (ClutterMedia *media,
const char *uri);
const char *(*get_uri) (ClutterMedia *media);
void (*set_playing) (ClutterMedia *media,
gboolean playing);
gboolean (*get_playing) (ClutterMedia *media);
void (*set_position) (ClutterMedia *media,
int position);
int (*get_position) (ClutterMedia *media);
void (*set_volume) (ClutterMedia *media,
double volume);
double (*get_volume) (ClutterMedia *media);
gboolean (*can_seek) (ClutterMedia *media);
int (*get_buffer_percent) (ClutterMedia *media);
int (*get_duration) (ClutterMedia *media);
/* signals */
void (* metadata_available) (ClutterMedia *media,
GstTagList *tag_list);
void (* eos) (ClutterMedia *media);
void (* error) (ClutterMedia *media,
GError *error);
};
GType clutter_media_get_type (void);
void
clutter_media_set_uri (ClutterMedia *media,
const char *uri);
const char *
clutter_media_get_uri (ClutterMedia *media);
void
clutter_media_set_playing (ClutterMedia *media,
gboolean playing);
gboolean
clutter_media_get_playing (ClutterMedia *media);
void
clutter_media_set_position (ClutterMedia *media,
int position);
int
clutter_media_get_position (ClutterMedia *media);
void
clutter_media_set_volume (ClutterMedia *media,
double volume);
double
clutter_media_get_volume (ClutterMedia *media);
gboolean
clutter_media_get_can_seek (ClutterMedia *media);
int
clutter_media_get_buffer_percent (ClutterMedia *media);
int
clutter_media_get_duration (ClutterMedia *media);
void
clutter_media_set_filename (ClutterMedia *media,
const gchar *filename);
G_END_DECLS
#endif

View file

@ -1,913 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:clutter-video-texture
* @short_description: Actor for playback of video files.
*
* #ClutterVideoTexture is a #ClutterTexture that plays video files.
*/
#include "clutter-video-texture.h"
#include "clutter-main.h"
#include "clutter-private.h" /* for DBG */
#include "clutter-marshal.h"
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/audio/gstbaseaudiosink.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include <glib.h>
struct _ClutterVideoTexturePrivate
{
GstElement *playbin;
char *uri;
gboolean can_seek;
int buffer_percent;
int duration;
gboolean force_aspect_ratio;
guint tick_timeout_id;
};
enum {
PROP_0,
/* ClutterMedia proprs */
PROP_URI,
PROP_PLAYING,
PROP_POSITION,
PROP_VOLUME,
PROP_CAN_SEEK,
PROP_BUFFER_PERCENT,
PROP_DURATION,
/* Extra texture props */
PROP_FORCE_ASPECT_RATIO
};
#define TICK_TIMEOUT 0.5
static void clutter_media_init (ClutterMediaInterface *iface);
static gboolean tick_timeout (ClutterVideoTexture *video_texture);
G_DEFINE_TYPE_EXTENDED (ClutterVideoTexture, \
clutter_video_texture, \
CLUTTER_TYPE_TEXTURE, \
0, \
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MEDIA, \
clutter_media_init));
/* Interface implementation */
static void
set_uri (ClutterMedia *media,
const char *uri)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
GstState state, pending;
g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
priv = video_texture->priv;
if (!priv->playbin)
return;
g_free (priv->uri);
if (uri)
{
priv->uri = g_strdup (uri);
/**
* Ensure the tick timeout is installed.
*
* We also have it installed in PAUSED state, because
* seeks etc may have a delayed effect on the position.
**/
if (priv->tick_timeout_id == 0)
{
priv->tick_timeout_id = g_timeout_add (TICK_TIMEOUT * 1000,
(GSourceFunc) tick_timeout,
video_texture);
}
}
else
{
priv->uri = NULL;
if (priv->tick_timeout_id > 0)
{
g_source_remove (priv->tick_timeout_id);
priv->tick_timeout_id = 0;
}
}
priv->can_seek = FALSE;
priv->duration = 0;
gst_element_get_state (priv->playbin, &state, &pending, 0);
if (pending)
state = pending;
gst_element_set_state (priv->playbin, GST_STATE_NULL);
g_object_set (priv->playbin,
"uri", uri,
NULL);
/**
* Restore state.
**/
if (uri)
gst_element_set_state (priv->playbin, state);
/*
* Emit notififications for all these to make sure UI is not showing
* any properties of the old URI.
*/
g_object_notify (G_OBJECT (video_texture), "uri");
g_object_notify (G_OBJECT (video_texture), "can-seek");
g_object_notify (G_OBJECT (video_texture), "duration");
g_object_notify (G_OBJECT (video_texture), "position");
}
static const char *
get_uri (ClutterMedia *media)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), NULL);
priv = video_texture->priv;
return priv->uri;
}
static void
set_playing (ClutterMedia *media,
gboolean playing)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
priv = video_texture->priv;
if (!priv->playbin)
return;
if (priv->uri)
{
GstState state;
if (playing)
state = GST_STATE_PLAYING;
else
state = GST_STATE_PAUSED;
gst_element_set_state (video_texture->priv->playbin, state);
}
else
{
if (playing)
g_warning ("Tried to play, but no URI is loaded.");
}
g_object_notify (G_OBJECT (video_texture), "playing");
g_object_notify (G_OBJECT (video_texture), "position");
}
static gboolean
get_playing (ClutterMedia *media)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
GstState state, pending;
g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
priv = video_texture->priv;
if (!priv->playbin)
return FALSE;
gst_element_get_state (priv->playbin, &state, &pending, 0);
if (pending)
return (pending == GST_STATE_PLAYING);
else
return (state == GST_STATE_PLAYING);
}
static void
set_position (ClutterMedia *media,
int position) /* seconds */
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
GstState state, pending;
g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
priv = video_texture->priv;
if (!priv->playbin)
return;
gst_element_get_state (priv->playbin, &state, &pending, 0);
if (pending)
state = pending;
gst_element_set_state (priv->playbin, GST_STATE_PAUSED);
gst_element_seek (priv->playbin,
1.0,
GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET,
position * GST_SECOND,
0, 0);
gst_element_set_state (priv->playbin, state);
}
static int
get_position (ClutterMedia *media)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
GstQuery *query;
gint64 position;
g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
priv = video_texture->priv;
if (!priv->playbin)
return -1;
query = gst_query_new_position (GST_FORMAT_TIME);
if (gst_element_query (priv->playbin, query))
gst_query_parse_position (query, NULL, &position);
else
position = 0;
gst_query_unref (query);
return (position / GST_SECOND);
}
static void
set_volume (ClutterMedia *media,
double volume)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
// g_return_if_fail (volume >= 0.0 && volume <= GST_VOL_MAX);
priv = video_texture->priv;
if (!priv->playbin)
return;
g_object_set (G_OBJECT (video_texture->priv->playbin),
"volume", volume,
NULL);
g_object_notify (G_OBJECT (video_texture), "volume");
}
static double
get_volume (ClutterMedia *media)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
ClutterVideoTexturePrivate *priv;
double volume;
g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), 0.0);
priv = video_texture->priv;
if (!priv->playbin)
return 0.0;
g_object_get (priv->playbin,
"volume", &volume,
NULL);
return volume;
}
static gboolean
can_seek (ClutterMedia *media)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
return video_texture->priv->can_seek;
}
static int
get_buffer_percent (ClutterMedia *media)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
return video_texture->priv->buffer_percent;
}
static int
get_duration (ClutterMedia *media)
{
ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
return video_texture->priv->duration;
}
static void
clutter_media_init (ClutterMediaInterface *iface)
{
iface->set_uri = set_uri;
iface->get_uri = get_uri;
iface->set_playing = set_playing;
iface->get_playing = get_playing;
iface->set_position = set_position;
iface->get_position = get_position;
iface->set_volume = set_volume;
iface->get_volume = get_volume;
iface->can_seek = can_seek;
iface->get_buffer_percent = get_buffer_percent;
iface->get_duration = get_duration;
}
static void
clutter_video_texture_dispose (GObject *object)
{
ClutterVideoTexture *self;
ClutterVideoTexturePrivate *priv;
self = CLUTTER_VIDEO_TEXTURE(object);
priv = self->priv;
/* FIXME: flush an errors off bus ? */
/* gst_bus_set_flushing (priv->bus, TRUE); */
if (priv->playbin)
{
gst_element_set_state (priv->playbin, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (priv->playbin));
priv->playbin = NULL;
}
if (priv->tick_timeout_id > 0)
{
g_source_remove (priv->tick_timeout_id);
priv->tick_timeout_id = 0;
}
G_OBJECT_CLASS (clutter_video_texture_parent_class)->dispose (object);
}
static void
clutter_video_texture_finalize (GObject *object)
{
ClutterVideoTexture *self;
ClutterVideoTexturePrivate *priv;
self = CLUTTER_VIDEO_TEXTURE(object);
priv = self->priv;
if (priv->uri)
g_free(priv->uri);
G_OBJECT_CLASS (clutter_video_texture_parent_class)->finalize (object);
}
static void
clutter_video_texture_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterVideoTexture *video_texture;
video_texture = CLUTTER_VIDEO_TEXTURE(object);
switch (property_id)
{
case PROP_URI:
clutter_media_set_uri (CLUTTER_MEDIA(video_texture),
g_value_get_string (value));
break;
case PROP_PLAYING:
clutter_media_set_playing (CLUTTER_MEDIA(video_texture),
g_value_get_boolean (value));
break;
case PROP_POSITION:
clutter_media_set_position (CLUTTER_MEDIA(video_texture),
g_value_get_int (value));
break;
case PROP_VOLUME:
clutter_media_set_volume (CLUTTER_MEDIA(video_texture),
g_value_get_double (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
clutter_video_texture_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
ClutterVideoTexture *video_texture;
ClutterMedia *media;
video_texture = CLUTTER_VIDEO_TEXTURE (object);
media = CLUTTER_MEDIA (video_texture);
switch (property_id)
{
case PROP_URI:
g_value_set_string (value, clutter_media_get_uri (media));
break;
case PROP_PLAYING:
g_value_set_boolean (value, clutter_media_get_playing (media));
break;
case PROP_POSITION:
g_value_set_int (value, clutter_media_get_position (media));
break;
case PROP_VOLUME:
g_value_set_double (value, clutter_media_get_volume (media));
break;
case PROP_CAN_SEEK:
g_value_set_boolean (value, clutter_media_get_can_seek (media));
break;
case PROP_BUFFER_PERCENT:
g_value_set_int (value, clutter_media_get_buffer_percent (media));
break;
case PROP_DURATION:
g_value_set_int (value, clutter_media_get_duration (media));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
clutter_video_texture_class_init (ClutterVideoTextureClass *klass)
{
GObjectClass *object_class;
ClutterActorClass *actor_class;
object_class = (GObjectClass*)klass;
actor_class = (ClutterActorClass*)klass;
object_class->dispose = clutter_video_texture_dispose;
object_class->finalize = clutter_video_texture_finalize;
object_class->set_property = clutter_video_texture_set_property;
object_class->get_property = clutter_video_texture_get_property;
/* Interface props */
g_object_class_override_property (object_class, PROP_URI, "uri");
g_object_class_override_property (object_class, PROP_PLAYING, "playing");
g_object_class_override_property (object_class, PROP_POSITION, "position");
g_object_class_override_property (object_class, PROP_VOLUME, "volume");
g_object_class_override_property (object_class, PROP_CAN_SEEK, "can-seek");
g_object_class_override_property (object_class, PROP_DURATION, "duration");
g_object_class_override_property (object_class, PROP_BUFFER_PERCENT,
"buffer-percent" );
}
static void
bus_message_error_cb (GstBus *bus,
GstMessage *message,
ClutterVideoTexture *video_texture)
{
GError *error;
error = NULL;
gst_message_parse_error (message, &error, NULL);
g_signal_emit_by_name (CLUTTER_MEDIA(video_texture), "error", error);
g_error_free (error);
}
static void
bus_message_eos_cb (GstBus *bus,
GstMessage *message,
ClutterVideoTexture *video_texture)
{
g_object_notify (G_OBJECT (video_texture), "position");
g_signal_emit_by_name (CLUTTER_MEDIA(video_texture), "eos");
}
static void
bus_message_tag_cb (GstBus *bus,
GstMessage *message,
ClutterVideoTexture *video_texture)
{
GstTagList *tag_list;
gst_message_parse_tag (message, &tag_list);
g_signal_emit_by_name (CLUTTER_MEDIA(video_texture),
"metadata-available",
tag_list);
gst_tag_list_free (tag_list);
}
static void
bus_message_buffering_cb (GstBus *bus,
GstMessage *message,
ClutterVideoTexture *video_texture)
{
const GstStructure *str;
str = gst_message_get_structure (message);
if (!str)
return;
if (!gst_structure_get_int (str,
"buffer-percent",
&video_texture->priv->buffer_percent))
return;
g_object_notify (G_OBJECT (video_texture), "buffer-percent");
}
static void
bus_message_duration_cb (GstBus *bus,
GstMessage *message,
ClutterVideoTexture *video_texture)
{
GstFormat format;
gint64 duration;
gst_message_parse_duration (message,
&format,
&duration);
if (format != GST_FORMAT_TIME)
return;
video_texture->priv->duration = duration / GST_SECOND;
g_object_notify (G_OBJECT (video_texture), "duration");
}
static void
bus_message_actor_cb (GstBus *bus,
GstMessage *message,
ClutterVideoTexture *video_texture)
{
const GstStructure *str;
str = gst_message_get_structure (message);
if (!str)
return;
}
static void
bus_message_state_change_cb (GstBus *bus,
GstMessage *message,
ClutterVideoTexture *video_texture)
{
gpointer src;
GstState old_state, new_state;
src = GST_MESSAGE_SRC (message);
if (src != video_texture->priv->playbin)
return;
gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
if (old_state == GST_STATE_READY &&
new_state == GST_STATE_PAUSED)
{
GstQuery *query;
/**
* Determine whether we can seek.
**/
query = gst_query_new_seeking (GST_FORMAT_TIME);
if (gst_element_query (video_texture->priv->playbin, query)) {
gst_query_parse_seeking (query,
NULL,
&video_texture->priv->can_seek,
NULL,
NULL);
} else {
/*
* Could not query for ability to seek. Determine
* using URI.
*/
if (g_str_has_prefix (video_texture->priv->uri,
"http://")) {
video_texture->priv->can_seek = FALSE;
} else {
video_texture->priv->can_seek = TRUE;
}
}
gst_query_unref (query);
g_object_notify (G_OBJECT (video_texture), "can-seek");
/**
* Determine the duration.
**/
query = gst_query_new_duration (GST_FORMAT_TIME);
if (gst_element_query (video_texture->priv->playbin, query))
{
gint64 duration;
gst_query_parse_duration (query, NULL, &duration);
video_texture->priv->duration = duration / GST_SECOND;
g_object_notify (G_OBJECT (video_texture), "duration");
}
gst_query_unref (query);
}
}
static gboolean
tick_timeout (ClutterVideoTexture *video_texture)
{
g_object_notify (G_OBJECT (video_texture), "position");
return TRUE;
}
static void
fakesink_handoff_cb (GstElement *fakesrc,
GstBuffer *buffer,
GstPad *pad,
gpointer user_data)
{
GstStructure *structure;
int width, height;
GdkPixbuf *pixb;
structure = gst_caps_get_structure(GST_CAPS(buffer->caps), 0);
gst_structure_get_int(structure, "width", &width);
gst_structure_get_int(structure, "height", &height);
/* FIXME: We really dont want to do this every time as gobject creation
* really need a clutter_texture_set_from_data call ?
*/
pixb = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
GDK_COLORSPACE_RGB,
FALSE,
8,
width,
height,
(3 * width + 3) &~ 3,
NULL,
NULL);
if (pixb)
{
clutter_texture_set_pixbuf (CLUTTER_TEXTURE(user_data), pixb);
g_object_unref(G_OBJECT(pixb));
}
}
static gboolean
lay_pipeline (ClutterVideoTexture *video_texture)
{
ClutterVideoTexturePrivate *priv;
GstElement *audio_sink = NULL;
GstElement *video_sink, *video_bin, *video_capsfilter;
GstCaps *video_filtercaps;
GstPad *video_ghost_pad;
priv = video_texture->priv;
priv->playbin = gst_element_factory_make ("playbin", "playbin");
if (!priv->playbin)
{
g_warning ("Unable to create playbin GST actor.");
return FALSE;
}
audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
if (!audio_sink)
{
audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
if (!audio_sink)
{
audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
g_warning ("Could not create a GST audio_sink. "
"Audio unavailable.");
if (!audio_sink) /* Need to bother ? */
audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
}
}
video_sink = gst_element_factory_make ("fakesink", "fakesink");
if (video_sink == NULL)
{
g_warning ("Could not create actor 'fakesink' for video playback");
priv->playbin = NULL;
return FALSE;
}
video_bin = gst_bin_new ("video-bin");
video_capsfilter = gst_element_factory_make ("capsfilter",
"video-capsfilter");
video_filtercaps
= gst_caps_new_simple("video/x-raw-rgb",
"bpp", G_TYPE_INT, 24,
"depth", G_TYPE_INT, 24,
"endianness", G_TYPE_INT, G_BIG_ENDIAN,
/* >> 8 for 24bpp */
"red_mask", G_TYPE_INT, 0xff0000,
"green_mask", G_TYPE_INT, 0xff00,
"blue_mask", G_TYPE_INT, 0xff,
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"framerate", GST_TYPE_FRACTION_RANGE,
0, 1, G_MAXINT, 1,
NULL);
g_object_set(G_OBJECT(video_capsfilter),
"caps", video_filtercaps,
NULL);
gst_bin_add(GST_BIN(video_bin), video_capsfilter);
gst_bin_add(GST_BIN(video_bin), video_sink);
gst_element_link (video_capsfilter, video_sink);
video_ghost_pad = gst_ghost_pad_new ("sink",
gst_element_get_pad (video_capsfilter,
"sink"));
gst_element_add_pad (video_bin, video_ghost_pad);
g_object_set (G_OBJECT(video_sink),
"signal-handoffs", TRUE,
"sync", TRUE,
/* Enable frame drops. FIXME: export setting in API ? */
"qos", TRUE,
NULL);
g_signal_connect(G_OBJECT (video_sink),
"handoff",
G_CALLBACK(fakesink_handoff_cb),
video_texture);
g_object_set (G_OBJECT (priv->playbin),
"video-sink", video_bin,
"audio-sink", audio_sink,
NULL);
return TRUE;
}
static void
clutter_video_texture_init (ClutterVideoTexture *video_texture)
{
ClutterVideoTexturePrivate *priv;
GstBus *bus;
priv = g_new0 (ClutterVideoTexturePrivate, 1);
video_texture->priv = priv;
if (!lay_pipeline(video_texture))
{
g_warning("Failed to initiate suitable playback pipeline.");
return;
}
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->playbin));
gst_bus_add_signal_watch (bus);
g_signal_connect_object (bus,
"message::error",
G_CALLBACK (bus_message_error_cb),
video_texture,
0);
g_signal_connect_object (bus,
"message::eos",
G_CALLBACK (bus_message_eos_cb),
video_texture,
0);
g_signal_connect_object (bus,
"message::tag",
G_CALLBACK (bus_message_tag_cb),
video_texture,
0);
g_signal_connect_object (bus,
"message::buffering",
G_CALLBACK (bus_message_buffering_cb),
video_texture,
0);
g_signal_connect_object (bus,
"message::duration",
G_CALLBACK (bus_message_duration_cb),
video_texture,
0);
g_signal_connect_object (bus,
"message::actor",
G_CALLBACK (bus_message_actor_cb),
video_texture,
0);
g_signal_connect_object (bus,
"message::state-changed",
G_CALLBACK (bus_message_state_change_cb),
video_texture,
0);
gst_object_unref (GST_OBJECT (bus));
return;
}
/**
* clutter_video_texture_new:
*
* Creates a video texture.
*
* Return value: A #ClutterActor implementing a displaying a video texture.
*/
ClutterActor*
clutter_video_texture_new (void)
{
ClutterVideoTexture *video_texture;
video_texture = g_object_new (CLUTTER_TYPE_VIDEO_TEXTURE,
"tiled", FALSE,
"pixel-format", GL_RGB,
/* As RGB below needed for Big Endian */
"pixel-type", GL_UNSIGNED_BYTE,
NULL);
return CLUTTER_ACTOR(video_texture);
}

View file

@ -1,89 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _HAVE_CLUTTER_VIDEO_TEXTURE_H
#define _HAVE_CLUTTER_VIDEO_TEXTURE_H
#include <glib-object.h>
#include <clutter/clutter-actor.h>
#include <clutter/clutter-texture.h>
#include <clutter/clutter-media.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_VIDEO_TEXTURE clutter_video_texture_get_type()
#define CLUTTER_VIDEO_TEXTURE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
CLUTTER_TYPE_VIDEO_TEXTURE, ClutterVideoTexture))
#define CLUTTER_VIDEO_TEXTURE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
CLUTTER_TYPE_VIDEO_TEXTURE, ClutterVideoTextureClass))
#define CLUTTER_IS_VIDEO_TEXTURE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
CLUTTER_TYPE_VIDEO_TEXTURE))
#define CLUTTER_IS_VIDEO_TEXTURE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
CLUTTER_TYPE_VIDEO_TEXTURE))
#define CLUTTER_VIDEO_TEXTURE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
CLUTTER_TYPE_VIDEO_TEXTURE, ClutterVideoTextureClass))
typedef struct _ClutterVideoTexture ClutterVideoTexture;
typedef struct _ClutterVideoTextureClass ClutterVideoTextureClass;
typedef struct _ClutterVideoTexturePrivate ClutterVideoTexturePrivate;
/* #define CLUTTER_VIDEO_TEXTURE_ERROR clutter_video_texture_error_quark() */
struct _ClutterVideoTexture
{
ClutterTexture parent;
ClutterVideoTexturePrivate *priv;
};
struct _ClutterVideoTextureClass
{
ClutterTextureClass parent_class;
/* Future padding */
void (* _clutter_reserved1) (void);
void (* _clutter_reserved2) (void);
void (* _clutter_reserved3) (void);
void (* _clutter_reserved4) (void);
void (* _clutter_reserved5) (void);
void (* _clutter_reserved6) (void);
};
GType clutter_video_texture_get_type (void) G_GNUC_CONST;
ClutterActor *clutter_video_texture_new (void);
G_END_DECLS
#endif

View file

@ -3,7 +3,6 @@
#include "clutter-keysyms.h"
#include "clutter-main.h"
#include "clutter-media.h"
#include "clutter-color.h"
#include "clutter-util.h"
#include "clutter-event.h"
@ -16,10 +15,8 @@
#include "clutter-group.h"
#include "clutter-texture.h"
#include "clutter-clone-texture.h"
#include "clutter-video-texture.h"
#include "clutter-label.h"
#include "clutter-alpha.h"
#include "clutter-audio.h"
#include "clutter-enum-types.h"
#endif

View file

@ -94,15 +94,6 @@ PKG_CHECK_MODULES(CLUTTER_DEPS, [$pkg_modules])
dnl ========================================================================
GST_MAJORMINOR=0.10
pkg_modules="gstreamer-$GST_MAJORMINOR gstreamer-plugins-base-$GST_MAJORMINOR"
PKG_CHECK_MODULES(GST, [$pkg_modules])
GST_LIBS="$GST_LIBS -lgstinterfaces-$GST_MAJORMINOR -lgstvideo-$GST_MAJORMINOR -lgstaudio-$GST_MAJORMINOR"
dnl ========================================================================
AC_ARG_ENABLE(gtk,
[AC_HELP_STRING([--enable-gtk], [Buld Gtk+ Clutter widget])],enable_gtk="$enableval",enable_gtk=no)
@ -125,8 +116,6 @@ GTK_DOC_CHECK([1.0])
dnl ========================================================================
AC_SUBST(GCC_FLAGS)
AC_SUBST(GST_CFLAGS)
AC_SUBST(GST_LIBS)
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)

View file

@ -1,3 +1,7 @@
2006-08-30 Jorn Baayen <jorn@openedhand.com>
* Makefile.am:
2006-07-06 Emmanuele Bassi <ebassi@openedhand.com>
* clutter-sections.txt: Add clutter_actor_has_clip() and

View file

@ -72,8 +72,7 @@ expand_content_files=
# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
# FIXME: $(GST_CFLAGS) needed for clutter_media metadata - togo..
INCLUDES=-I$(top_srcdir) $(CLUTTER_CFLAGS) $(GST_CFLAGS)
INCLUDES=-I$(top_srcdir) $(CLUTTER_CFLAGS)
GTKDOC_LIBS=$(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la $(CLUTTER_LIBS)
# This includes the standard gtk-doc make rules, copied by gtkdocize.

View file

@ -1,51 +1,29 @@
noinst_PROGRAMS = test video-player video-cube super-oh behave
noinst_PROGRAMS = test super-oh behave
INCLUDES = -I$(top_srcdir)/
test_SOURCES = test.c
test_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
test_CFLAGS = $(CLUTTER_CFLAGS) $(GCONF_CFLAGS)
test_LDFLAGS = \
$(CLUTTER_LIBS) \
$(GST_LIBS) \
$(GCONF_LIBS) \
$(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la
video_player_SOURCES = video-player.c
video_player_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
video_player_LDFLAGS = \
$(CLUTTER_LIBS) \
$(GST_LIBS) \
$(GCONF_LIBS) \
$(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la
video_cube_SOURCES = video-cube.c
video_cube_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
video_cube_LDFLAGS = \
$(CLUTTER_LIBS) \
$(GST_LIBS) \
$(GCONF_LIBS) \
$(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la
super_oh_SOURCES = super-oh.c
super_oh_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
super_oh_CFLAGS = $(CLUTTER_CFLAGS) $(GCONF_CFLAGS)
super_oh_LDFLAGS = \
$(CLUTTER_LIBS) \
$(GST_LIBS) \
$(GCONF_LIBS) \
$(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la
behave_SOURCES = behave.c
behave_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
behave_CFLAGS = $(CLUTTER_CFLAGS) $(GCONF_CFLAGS)
behave_LDFLAGS = \
$(CLUTTER_LIBS) \
$(GST_LIBS) \
$(GCONF_LIBS) \
$(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la
EXTRA_DIST = redhand.png \
clutter-logo-800x600.png \
media-actions-pause.png \
media-actions-start.png \
vid-panel.png \
README

View file

@ -18,19 +18,6 @@ There are:
Spinning OH logos. Click to dissapear.
o video-player.
Simple fullscreen video player.
- Move mouse to see controls.
- Hit q or Esc to exit, p to toggle pause state.
- Has some useless cheesy effects built in.
- Hit e to flip the video.
o video-cube.
Pure evil. A nasty hack to do a video cube with clutter.
Could be done much nicer.
Also see http://svn.o-hand.com/repos/misc/trunk/opt for a simple

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

View file

@ -1,272 +0,0 @@
/* HACK HACK. HACK.
* This is just a quick hack to see if a 3D type video cube
* would be possible with clutter. It needs many hacks cleaning.
*/
#include <clutter/clutter.h>
#include <glib-object.h>
#include <math.h> /* for M_PI */
#define WINWIDTH 800
#define WINHEIGHT 600
/* lazy globals */
static float xrot, yrot, zrot;
/* Avoid needing GLUT perspective call */
static void
frustum (GLfloat left,
GLfloat right,
GLfloat bottom,
GLfloat top,
GLfloat nearval,
GLfloat farval)
{
GLfloat x, y, a, b, c, d;
GLfloat m[16];
x = (2.0 * nearval) / (right - left);
y = (2.0 * nearval) / (top - bottom);
a = (right + left) / (right - left);
b = (top + bottom) / (top - bottom);
c = -(farval + nearval) / ( farval - nearval);
d = -(2.0 * farval * nearval) / (farval - nearval);
#define M(row,col) m[col*4+row]
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
#undef M
glMultMatrixf (m);
}
static void
perspective (GLfloat fovy,
GLfloat aspect,
GLfloat zNear,
GLfloat zFar)
{
GLfloat xmin, xmax, ymin, ymax;
ymax = zNear * tan (fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
frustum (xmin, xmax, ymin, ymax, zNear, zFar);
}
/* video texture subclass */
#define CLUTTER_TYPE_VIDEO_TEXTURE_CUBE clutter_video_texture_cube_get_type()
#define CLUTTER_VIDEO_TEXTURE_CUBE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
CLUTTER_TYPE_VIDEO_TEXTURE_CUBE, ClutterVideoTextureCube))
#define CLUTTER_VIDEO_TEXTURE_CUBE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
CLUTTER_TYPE_VIDEO_TEXTURE_CUBE, ClutterVideoTextureCubeClass))
#define CLUTTER_IS_VIDEO_TEXTURE_CUBE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
CLUTTER_TYPE_VIDEO_TEXTURE_CUBE))
#define CLUTTER_IS_VIDEO_TEXTURE_CUBE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
CLUTTER_TYPE_VIDEO_TEXTURE_CUBE))
#define CLUTTER_VIDEO_TEXTURE_CUBE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
CLUTTER_TYPE_VIDEO_TEXTURE_CUBE, ClutterVideoTextureCubeClass))
typedef struct ClutterVideoTextureCubePrivate ClutterVideoTextureCubePrivate ;
typedef struct ClutterVideoTextureCube
{
ClutterVideoTexture parent;
ClutterVideoTextureCubePrivate *priv;
}
ClutterVideoTextureCube;
typedef struct ClutterVideoTextureCubeClass
{
ClutterVideoTextureClass parent_class;
}
ClutterVideoTextureCubeClass;
GType clutter_video_texture_cube_get_type (void);
G_DEFINE_TYPE (ClutterVideoTextureCube, clutter_video_texture_cube, CLUTTER_TYPE_VIDEO_TEXTURE);
static void
clutter_video_texture_cube_paint (ClutterActor *self)
{
if (clutter_texture_get_pixbuf (CLUTTER_TEXTURE(self)) == NULL)
return;
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR(self)))
clutter_actor_realize (CLUTTER_ACTOR(self));
if (!clutter_texture_has_generated_tiles (CLUTTER_TEXTURE(self)))
return;
/* HACK: sets up a 3D tranform matrix other than regular 2D one */
/* FIXME: figure out how to nicely combine both within clutter */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
perspective (45.0f,
(GLfloat)WINWIDTH/(GLfloat)WINHEIGHT,
0.1f,
100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* back camera out a little */
glTranslatef(0.0f,0.0f,-3.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
/* HACK: Cheat as just bind to first tiled as squared */
clutter_texture_bind_tile (CLUTTER_TEXTURE(self), 0);
glBegin(GL_QUADS);
// Front Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// Top Face
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// Bottom Face
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// Left Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
/* HACK: reset to regular transform */
#if 0
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, WINWIDTH, WINHEIGHT, 0, -1, 1);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
#endif
/* rotate */
xrot+=1.0f;
yrot+=1.0f;
zrot+=1.0f;
}
static void
clutter_video_texture_cube_class_init (ClutterVideoTextureCubeClass *klass)
{
GObjectClass *gobject_class;
ClutterActorClass *actor_class;
gobject_class = (GObjectClass*)klass;
actor_class = (ClutterActorClass*)klass;
actor_class->paint = clutter_video_texture_cube_paint;
}
static void
clutter_video_texture_cube_init (ClutterVideoTextureCube *self)
{
}
ClutterActor*
clutter_video_texture_cube_new (GError **err)
{
return CLUTTER_ACTOR(g_object_new (CLUTTER_TYPE_VIDEO_TEXTURE_CUBE,
/* "tiled", FALSE, */
NULL));
}
int
main (int argc, char *argv[])
{
ClutterActor *label, *texture, *vtexture;
ClutterActor *stage;
GdkPixbuf *pixbuf;
GError *err = NULL;
if (argc < 2)
g_error("%s <video file>", argv[0]);
clutter_init (&argc, &argv);
stage = clutter_stage_get_default ();
g_signal_connect (stage, "key-press-event",
G_CALLBACK (clutter_main_quit), NULL);
pixbuf = gdk_pixbuf_new_from_file ("clutter-logo-800x600.png", NULL);
if (!pixbuf)
g_error("pixbuf load failed");
clutter_actor_set_size (stage,
WINWIDTH, WINHEIGHT);
texture = clutter_texture_new_from_pixbuf (pixbuf);
vtexture = clutter_video_texture_cube_new (&err);
if (vtexture == NULL || err != NULL)
{
g_error("failed to create vtexture, err: %s", err->message);
}
clutter_media_set_filename (CLUTTER_MEDIA(vtexture), argv[1]);
clutter_group_add (CLUTTER_GROUP (stage), texture);
clutter_group_add (CLUTTER_GROUP (stage), vtexture);
clutter_group_show_all (CLUTTER_GROUP (stage));
clutter_media_set_playing(CLUTTER_MEDIA(vtexture), TRUE);
clutter_main();
return 0;
}

View file

@ -1,381 +0,0 @@
#include <clutter/clutter.h>
#define SEEK_H 20
#define SEEK_W 690
typedef struct VideoApp
{
ClutterActor *vtexture;
ClutterActor *control, *control_bg, *control_play, *control_pause,
*control_seek1, *control_seek2, *control_seekbar, *control_label;
gboolean controls_showing, paused;
guint controls_timeout;
ClutterTimeline *controls_tl, *effect1_tl;
}
VideoApp;
static void
show_controls (VideoApp *app, gboolean vis);
void
control_tl_cb (ClutterTimeline *timeline,
gint frame_num,
VideoApp *app)
{
guint8 opacity;
clutter_group_show_all (CLUTTER_GROUP (app->control));
clutter_actor_hide (app->paused ? app->control_pause : app->control_play);
clutter_actor_show (app->paused ? app->control_play : app->control_pause);
opacity = ( frame_num * 0xde ) / clutter_timeline_get_n_frames(timeline);
if (!app->controls_showing)
opacity = 0xde - opacity;
clutter_actor_set_opacity (app->control, opacity);
}
void
control_tl_complete_cb (ClutterTimeline *timeline,
VideoApp *app)
{
if (!app->controls_showing)
clutter_group_hide_all (CLUTTER_GROUP (app->control));
app->controls_timeout = 0;
}
static gboolean
controls_timeout_cb (VideoApp *app)
{
show_controls (app, FALSE);
return FALSE;
}
static void
show_controls (VideoApp *app, gboolean vis)
{
if (clutter_timeline_is_playing (app->controls_tl))
return;
if (vis == TRUE && app->controls_showing == FALSE)
{
app->controls_showing = TRUE;
clutter_timeline_start (app->controls_tl);
app->controls_timeout = g_timeout_add (5 * 1000,
(GSourceFunc)controls_timeout_cb,
app);
return;
}
if (vis == TRUE && app->controls_showing == TRUE)
{
if (app->controls_timeout)
{
g_source_remove (app->controls_timeout);
app->controls_timeout
= g_timeout_add (5 * 1000,
(GSourceFunc)controls_timeout_cb,
app);
}
return;
}
if (vis == FALSE && app->controls_showing == TRUE)
{
app->controls_showing = FALSE;
clutter_timeline_start (app->controls_tl);
return;
}
}
void
toggle_pause_state (VideoApp *app)
{
if (app->paused)
{
clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture),
TRUE);
app->paused = FALSE;
clutter_actor_hide (app->control_play);
clutter_actor_show (app->control_pause);
}
else
{
clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture),
FALSE);
app->paused = TRUE;
clutter_actor_hide (app->control_pause);
clutter_actor_show (app->control_play);
}
}
void
input_cb (ClutterStage *stage,
ClutterEvent *event,
gpointer user_data)
{
VideoApp *app = (VideoApp*)user_data;
switch (event->type)
{
case CLUTTER_MOTION:
show_controls (app, TRUE);
break;
case CLUTTER_BUTTON_PRESS:
if (app->controls_showing)
{
ClutterActor *actor;
ClutterButtonEvent *bev = (ClutterButtonEvent *) event;
actor
= clutter_stage_get_actor_at_pos
(CLUTTER_STAGE(clutter_stage_get_default()),
bev->x, bev->y);
if (actor == app->control_pause || actor == app->control_play)
{
toggle_pause_state (app);
return;
}
if (actor == app->control_seek1
|| actor == app->control_seek2
|| actor == app->control_seekbar)
{
gint x, y, dist, pos;
clutter_actor_get_abs_position (app->control_seekbar, &x, &y);
dist = bev->x - x;
CLAMP(dist, 0, SEEK_W);
pos = (dist * clutter_media_get_duration
(CLUTTER_MEDIA(app->vtexture))) / SEEK_W;
clutter_media_set_position (CLUTTER_MEDIA(app->vtexture),
pos);
}
}
break;
case CLUTTER_KEY_RELEASE:
{
ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
switch (clutter_key_event_symbol (kev))
{
case CLUTTER_q:
case CLUTTER_Escape:
clutter_main_quit ();
break;
case CLUTTER_e:
if (!clutter_timeline_is_playing (app->effect1_tl))
clutter_timeline_start (app->effect1_tl);
break;
default:
toggle_pause_state (app);
break;
}
}
default:
break;
}
}
void
size_change (ClutterTexture *texture,
gint width,
gint height,
gpointer user_data)
{
ClutterActor *stage;
ClutterGeometry stage_geom;
gint vid_width, vid_height, new_y, new_height;
clutter_texture_get_base_size (texture, &vid_width, &vid_height);
new_height = ( vid_height * CLUTTER_STAGE_WIDTH() ) / vid_width;
new_y = ( (gint)CLUTTER_STAGE_HEIGHT() - new_height) / 2;
clutter_actor_set_position (CLUTTER_ACTOR (texture), 0, new_y);
clutter_actor_set_size (CLUTTER_ACTOR (texture),
CLUTTER_STAGE_WIDTH(),
new_height);
}
void
tick (GObject *object,
GParamSpec *pspec,
VideoApp *app)
{
ClutterVideoTexture *vtex;
gint w, h, position, duration, seek_w;
gchar buf[256];
vtex = CLUTTER_VIDEO_TEXTURE(object);
position = clutter_media_get_position (CLUTTER_MEDIA(vtex));
duration = clutter_media_get_duration (CLUTTER_MEDIA(vtex));
if (duration == 0 || position == 0)
return;
clutter_actor_set_size (app->control_seekbar,
(position * SEEK_W) / duration,
SEEK_H);
}
int
effect1_tl_cb (ClutterTimeline *timeline,
gint frame_num,
VideoApp *app)
{
clutter_actor_rotate_y (app->vtexture,
frame_num * 12,
CLUTTER_STAGE_WIDTH()/2,
0);
}
int
main (int argc, char *argv[])
{
VideoApp *app = NULL;
ClutterActor *stage;
ClutterColor stage_color = { 0x00, 0x00, 0x00, 0x00 };
ClutterColor control_color1 = { 73, 74, 77, 0xee };
ClutterColor control_color2 = { 0xcc, 0xcc, 0xcc, 0xff };
GdkPixbuf *pixb;
gint x,y;
if (argc < 2)
g_error("%s <video file>", argv[0]);
clutter_init (&argc, &argv);
stage = clutter_stage_get_default ();
g_object_set (stage, "fullscreen", TRUE, NULL);
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
app = g_new0(VideoApp, 1);
app->vtexture = clutter_video_texture_new ();
if (app->vtexture == NULL)
{
g_error("failed to create vtexture");
}
/* Dont let the underlying pixbuf dictate size */
g_object_set (G_OBJECT(app->vtexture), "sync-size", FALSE, NULL);
/* Handle it ourselves so can scale up for fullscreen better */
g_signal_connect (CLUTTER_TEXTURE(app->vtexture),
"size-change",
G_CALLBACK (size_change), NULL);
/* Load up out video texture */
clutter_media_set_filename(CLUTTER_MEDIA(app->vtexture), argv[1]);
/* Create the control UI */
app->control = clutter_group_new ();
pixb = gdk_pixbuf_new_from_file ("vid-panel.png", NULL);
if (pixb == NULL)
g_error("Unable to load vid-panel.png");
app->control_bg = clutter_texture_new_from_pixbuf (pixb);
pixb = gdk_pixbuf_new_from_file("media-actions-start.png", NULL);
if (pixb == NULL)
g_error("Unable to load media-actions-start.png");
app->control_play = clutter_texture_new_from_pixbuf (pixb);
pixb = gdk_pixbuf_new_from_file("media-actions-pause.png", NULL);
if (pixb == NULL)
g_error("Unable to load media-actions-pause.png");
app->control_pause = clutter_texture_new_from_pixbuf (pixb);
app->control_seek1 = clutter_rectangle_new_with_color (&control_color1);
app->control_seek2 = clutter_rectangle_new_with_color (&control_color2);
app->control_seekbar = clutter_rectangle_new_with_color (&control_color1);
clutter_actor_set_opacity (app->control_seekbar, 0x99);
app->control_label
= clutter_label_new_with_text("Sans Bold 24",
g_path_get_basename(argv[1]));
clutter_label_set_color (CLUTTER_LABEL(app->control_label), &control_color1);
clutter_group_add_many (CLUTTER_GROUP (app->control),
app->control_bg,
app->control_play,
app->control_pause,
app->control_seek1,
app->control_seek2,
app->control_seekbar,
app->control_label,
NULL);
x = (CLUTTER_STAGE_WIDTH() - clutter_actor_get_width(app->control))/2;
y = CLUTTER_STAGE_HEIGHT() - (CLUTTER_STAGE_HEIGHT()/3);
clutter_actor_set_position (app->control, x, y);
clutter_actor_set_opacity (app->control, 0xee);
clutter_actor_set_position (app->control_play, 30, 30);
clutter_actor_set_position (app->control_pause, 30, 30);
clutter_actor_set_size (app->control_seek1, SEEK_W+10, SEEK_H+10);
clutter_actor_set_position (app->control_seek1, 200, 100);
clutter_actor_set_size (app->control_seek2, SEEK_W, SEEK_H);
clutter_actor_set_position (app->control_seek2, 205, 105);
clutter_actor_set_size (app->control_seekbar, 0, SEEK_H);
clutter_actor_set_position (app->control_seekbar, 205, 105);
clutter_actor_set_position (app->control_label, 200, 40);
/* Add control UI to stage */
clutter_group_add_many (CLUTTER_GROUP (stage),
app->vtexture, app->control, NULL);
/* hook up a time line for fading controls */
app->controls_tl = clutter_timeline_new (10, 30);
g_signal_connect (app->controls_tl, "new-frame",
G_CALLBACK (control_tl_cb), app);
g_signal_connect (app->controls_tl, "completed",
G_CALLBACK (control_tl_complete_cb), app);
app->effect1_tl = clutter_timeline_new (30, 90);
g_signal_connect (app->effect1_tl, "new-frame",
G_CALLBACK (effect1_tl_cb), app);
/* Hook up other events */
g_signal_connect (stage, "input-event",
G_CALLBACK (input_cb),
app);
g_signal_connect (CLUTTER_MEDIA(app->vtexture),
"notify::position",
G_CALLBACK (tick),
app);
clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture), TRUE);
clutter_group_show_all (CLUTTER_GROUP (stage));
clutter_main();
return 0;
}

View file

@ -1,17 +0,0 @@
lib_LTLIBRARIES = libclutterimagesink.la
# HACK HACK HACK HACK for now
libdir= /usr/lib/gstreamer-0.10/
INCLUDES=@GST_CFLAGS@ $(CLUTTER_CFLAGS)
LIBS=@GST_LIBS@
libclutterimagesink_la_SOURCES = clutterimagesink.c
libclutterimagesink_la_INCLUDES = $(CLUTTER_CFLAGS)
libclutterimagesink_LIBDIR = ${libdir}/gst
libclutterimagesink_la_LIBADD = @CLUTTER_LIBS@
libclutterimagesink_la_LDFLAGS = -module -avoid-version
noinst_HEADERS = \
clutterimagesink.h

View file

@ -1,703 +0,0 @@
/* GStreamer
* Copyright (C) <2003> Julien Moutte <julien@moutte.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define DBG(x, a...) \
g_printerr ( __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a)
/* Object header */
#include "cltrimagesink.h"
/* Debugging category */
#include <gst/gstinfo.h>
GST_DEBUG_CATEGORY_STATIC (gst_debug_cltrimagesink);
#define GST_CAT_DEFAULT gst_debug_cltrimagesink
/* ElementFactory information */
static GstElementDetails gst_cltrimagesink_details =
GST_ELEMENT_DETAILS ("Video sink",
"Sink/Video",
"An Clutter based videosink",
"Matthew Allum <mallum@o-hand.com>");
/* Default template - initiated with class struct to allow gst-register to work
without X running */
static GstStaticPadTemplate gst_cltrimagesink_sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb, "
"framerate = (double) [ 1.0, 100.0 ], "
"width = (int) [ 1, MAX ], "
"height = (int) [ 1, MAX ]; "
"video/x-raw-yuv, "
"framerate = (double) [ 1.0, 100.0 ], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
);
/* CltrimageSink signals and args */
enum
{
SIGNAL_HANDOFF,
SIGNAL_BUFALLOC,
LAST_SIGNAL
/* FILL ME */
};
static guint gst_cltrimagesink_signals[LAST_SIGNAL] = { 0 };
enum
{
ARG_0,
ARG_QUEUE,
ARG_SYNCHRONOUS,
ARG_SIGNAL_HANDOFFS
/* FILL ME */
};
static GstVideoSinkClass *parent_class = NULL;
#define GLERR() \
{ \
GLenum err = glGetError (); /* Roundtrip */ \
if (err != GL_NO_ERROR) \
{ \
g_printerr (__FILE__ ": GL Error: %x [at %s:%d]\n", \
err, __func__, __LINE__); \
} \
}
/* ============================================================= */
/* */
/* Private Methods */
/* */
/* ============================================================= */
/*
=================
Element stuff
=================
*/
#define SWAP_4(x) ( ((x) << 24) | \
(((x) << 16) & 0x00ff0000) | \
(((x) << 8) & 0x0000ff00) | \
0x000000ff )
static GstCaps *
gst_cltrimagesink_fixate (GstPad *pad,
const GstCaps *caps)
{
GstStructure *structure;
GstCaps *newcaps;
if (gst_caps_get_size (caps) > 1)
return NULL;
newcaps = gst_caps_copy (caps);
structure = gst_caps_get_structure (newcaps, 0);
if (gst_caps_structure_fixate_field_nearest_int (structure, "width", 320))
{
return newcaps;
}
if (gst_caps_structure_fixate_field_nearest_int (structure, "height", 240))
{
return newcaps;
}
if (gst_caps_structure_fixate_field_nearest_double (structure,
"framerate",
30.0))
{
return newcaps;
}
gst_caps_free (newcaps);
return NULL;
}
static GstCaps *
gst_cltrimagesink_getcaps (GstPad * pad)
{
GstCltrimageSink *cltrimagesink;
cltrimagesink = GST_CLTRIMAGESINK (gst_pad_get_parent (pad));
if (!cltrimagesink->caps)
cltrimagesink->caps
= gst_caps_new_simple (
"video/x-raw-rgb",
"bpp", G_TYPE_INT, 24,
"depth", G_TYPE_INT, 24,
"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,
*/
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"framerate", GST_TYPE_DOUBLE_RANGE, 1.0, 100.0, NULL);
return gst_caps_copy (cltrimagesink->caps);
}
static GstPadLinkReturn
gst_cltrimagesink_sink_link (GstPad * pad, const GstCaps * caps)
{
GstCltrimageSink *cltrimagesink;
gboolean ret;
GstStructure *structure;
Pixbuf *pixb = NULL;
cltrimagesink = GST_CLTRIMAGESINK (gst_pad_get_parent (pad));
/*
if (!cltrimagesink->texture)
return GST_PAD_LINK_DELAYED;
*/
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "width",
&(GST_VIDEOSINK_WIDTH (cltrimagesink)));
ret &= gst_structure_get_int (structure, "height",
&(GST_VIDEOSINK_HEIGHT (cltrimagesink)));
ret &= gst_structure_get_double (structure,
"framerate", &cltrimagesink->framerate);
if (!ret)
{
DBG("!ret returning GST_PAD_LINK_REFUSED");
return GST_PAD_LINK_REFUSED;
}
cltrimagesink->pixel_width = 1;
gst_structure_get_int (structure, "pixel_width",
&cltrimagesink->pixel_width);
cltrimagesink->pixel_height = 1;
gst_structure_get_int (structure, "pixel_height",
&cltrimagesink->pixel_height);
DBG("returning GST_PAD_LINK_OK, with %ix%i or %ix%i",
cltrimagesink->pixel_width,
cltrimagesink->pixel_height,
GST_VIDEOSINK_WIDTH (cltrimagesink),
GST_VIDEOSINK_HEIGHT (cltrimagesink));
pixb = pixbuf_new(GST_VIDEOSINK_WIDTH (cltrimagesink),
GST_VIDEOSINK_HEIGHT (cltrimagesink));
DBG("pixbuf new at %ix%i", GST_VIDEOSINK_WIDTH (cltrimagesink),
GST_VIDEOSINK_HEIGHT (cltrimagesink));
/* Is this the right place ? */
cltrimagesink->texture = cltr_texture_no_tile_new(pixb);
pixbuf_unref(pixb);
return GST_PAD_LINK_OK;
}
static GstElementStateReturn
gst_cltrimagesink_change_state (GstElement * element)
{
GstCltrimageSink *cltrimagesink;
DBG("mark");
cltrimagesink = GST_CLTRIMAGESINK (element);
switch (GST_STATE_TRANSITION (element))
{
case GST_STATE_NULL_TO_READY:
/* Initializing the Context */
/*
if (!cltrimagesink->texture)
{
DBG("setting state to failure");
return GST_STATE_FAILURE;
}
*/
DBG("GST_STATE_NULL_TO_READY");
break;
case GST_STATE_READY_TO_PAUSED:
DBG("GST_STATE_READY_TO_PAUSED");
cltrimagesink->time = 0;
break;
case GST_STATE_PAUSED_TO_PLAYING:
DBG("GST_STATE_PAUSED_TO_PLAYING");
break;
case GST_STATE_PLAYING_TO_PAUSED:
DBG("GST_STATE_PLAYING_TO_PAUSED");
break;
case GST_STATE_PAUSED_TO_READY:
DBG("GST_STATE_PAUSED_TO_READY");
while (g_async_queue_try_pop (cltrimagesink->queue)) ;
cltrimagesink->framerate = 0;
GST_VIDEOSINK_WIDTH (cltrimagesink) = 0;
GST_VIDEOSINK_HEIGHT (cltrimagesink) = 0;
break;
case GST_STATE_READY_TO_NULL:
DBG("GST_STATE_READY_TO_NULL");
/*
if (cltrimagesink->texture)
cltr_texture_unref(cltrimagesink->texture);
*/
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
static void
gst_cltrimagesink_chain (GstPad * pad, GstData * data)
{
GstBuffer *buf = GST_BUFFER (data);
GstCltrimageSink *cltrimagesink;
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
cltrimagesink = GST_CLTRIMAGESINK (gst_pad_get_parent (pad));
if (GST_IS_EVENT (data))
{
gst_pad_event_default (pad, GST_EVENT (data));
DBG("GST_IS_EVENT, returning");
return;
}
buf = GST_BUFFER (data);
/* update time */
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf))
cltrimagesink->time = GST_BUFFER_TIMESTAMP (buf);
/* If this buffer has been allocated using our buffer management we
* simply put the ximage which is in the PRIVATE pointer */
#if 0
if (GST_BUFFER_FREE_DATA_FUNC (buf) == gst_cltrimagesink_buffer_free)
{
/*
gst_cltrimagesink_ximage_put (cltrimagesink, GST_BUFFER_PRIVATE (buf));
*/
}
else
#endif
{ /* Else we have to copy the data into our private image, */
/* if we have one... */
if (cltrimagesink->texture
&& GST_VIDEOSINK_WIDTH (cltrimagesink)
&& GST_VIDEOSINK_HEIGHT (cltrimagesink))
{
/* need to copy the data into out pixbuf here */
Pixbuf *pixb = NULL;
cltr_texture_lock(cltrimagesink->texture);
pixb = cltr_texture_get_pixbuf(cltrimagesink->texture);
if (pixb)
{
int i = 0;
guint8 *d = GST_BUFFER_DATA (buf);
for (i = 0; i < pixb->height * pixb->width; i++)
{
int r,g,b, a;
r = *d++; g = *d++; b = *d++; a = 0xff;
pixb->data[i] = ((r << 24) |
(g << 16) |
(b << 8) |
a );
}
/*
memcpy (pixb->data,
GST_BUFFER_DATA (buf),
MIN (GST_BUFFER_SIZE (buf),
pixb->bytes_per_line * pixb->width));
*/
/* Below faster but threading issues causing DRI to bomb out */
/*
if (GST_BUFFER_SIZE (buf) >= pixb->width * pixb->height * 3)
cltr_texture_force_rgb_data(cltrimagesink->texture,
pixb->width,
pixb->height,
GST_BUFFER_DATA (buf));
*/
}
cltr_texture_unlock(cltrimagesink->texture);
if (cltrimagesink->queue)
{
CltrVideoSignal *signal;
signal = g_new0 (CltrVideoSignal, 1);
signal->signal_id = CLTR_VIDEO_ASYNC_TEXTURE;
signal->signal_data.texture.ref = cltrimagesink->texture;
g_async_queue_push(cltrimagesink->queue,
(gpointer)signal);
}
}
else
{
/* No image available. Something went wrong during capsnego ! */
gst_buffer_unref (buf);
GST_ELEMENT_ERROR (cltrimagesink, CORE, NEGOTIATION, (NULL),
("no format defined before chain function"));
return;
}
}
/* swap buffer here ? */
GST_DEBUG ("clock wait: %" GST_TIME_FORMAT,
GST_TIME_ARGS (cltrimagesink->time));
/* ah, BTW, I think the gst_element_wait should happen _before_
the ximage is shown */
if (GST_VIDEOSINK_CLOCK (cltrimagesink))
gst_element_wait (GST_ELEMENT (cltrimagesink), cltrimagesink->time);
/* set correct time for next buffer */
if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf) && cltrimagesink->framerate > 0)
cltrimagesink->time += GST_SECOND / cltrimagesink->framerate;
gst_buffer_unref (buf);
/*
if (!cltrimagesink->signal_handoffs)
gst_cltrimagesink_handle_xevents (cltrimagesink, pad);
*/
}
/* =========================================== */
/* */
/* Init & Class init */
/* */
/* =========================================== */
static void
gst_cltrimagesink_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GstCltrimageSink *cltrimagesink;
g_return_if_fail (GST_IS_CLTRIMAGESINK (object));
cltrimagesink = GST_CLTRIMAGESINK (object);
switch (prop_id)
{
case ARG_QUEUE:
cltrimagesink->queue = g_value_get_pointer (value);
break;
/*
case ARG_SIGNAL_HANDOFFS:
cltrimagesink->signal_handoffs = g_value_get_boolean (value);
*/
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_cltrimagesink_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GstCltrimageSink *cltrimagesink;
g_return_if_fail (GST_IS_CLTRIMAGESINK (object));
cltrimagesink = GST_CLTRIMAGESINK (object);
switch (prop_id)
{
case ARG_QUEUE:
g_value_set_pointer (value, cltrimagesink->queue);
break;
/*
case ARG_SIGNAL_HANDOFFS:
g_value_set_boolean (value, cltrimagesink->signal_handoffs);
break;
*/
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_cltrimagesink_finalize (GObject *object)
{
GstCltrimageSink *cltrimagesink;
cltrimagesink = GST_CLTRIMAGESINK (object);
/*
if (cltrimagesink->display_name)
{
g_free (cltrimagesink->display_name);
cltrimagesink->display_name = NULL;
}
*/
g_mutex_free (cltrimagesink->x_lock);
g_mutex_free (cltrimagesink->pool_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_cltrimagesink_init (GstCltrimageSink * cltrimagesink)
{
GST_VIDEOSINK_PAD (cltrimagesink)
= gst_pad_new_from_template ( gst_static_pad_template_get(&gst_cltrimagesink_sink_template_factory), "sink");
gst_element_add_pad (GST_ELEMENT (cltrimagesink),
GST_VIDEOSINK_PAD (cltrimagesink));
gst_pad_set_chain_function (GST_VIDEOSINK_PAD (cltrimagesink),
gst_cltrimagesink_chain);
gst_pad_set_link_function (GST_VIDEOSINK_PAD (cltrimagesink),
gst_cltrimagesink_sink_link);
gst_pad_set_getcaps_function (GST_VIDEOSINK_PAD (cltrimagesink),
gst_cltrimagesink_getcaps);
gst_pad_set_fixate_function (GST_VIDEOSINK_PAD (cltrimagesink),
gst_cltrimagesink_fixate);
/*
gst_pad_set_bufferalloc_function (GST_VIDEOSINK_PAD (cltrimagesink),
gst_cltrimagesink_buffer_alloc);
*/
cltrimagesink->framerate = 0;
cltrimagesink->x_lock = g_mutex_new ();
cltrimagesink->pixel_width = cltrimagesink->pixel_height = 1;
cltrimagesink->image_pool = NULL;
cltrimagesink->pool_lock = g_mutex_new ();
cltrimagesink->texture = NULL;
GST_FLAG_SET (cltrimagesink, GST_ELEMENT_THREAD_SUGGESTED);
GST_FLAG_SET (cltrimagesink, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_cltrimagesink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (element_class, &gst_cltrimagesink_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_cltrimagesink_sink_template_factory));
}
static void
gst_cltrimagesink_class_init (GstCltrimageSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass*) klass;
gstelement_class = (GstElementClass*) klass;
parent_class = g_type_class_ref (GST_TYPE_VIDEOSINK);
/* TOGO */
g_object_class_install_property (gobject_class,
ARG_QUEUE,
g_param_spec_pointer ("queue",
"Queue",
"Async Signal Queue",
G_PARAM_READWRITE));
/* TOGO */
g_object_class_install_property (gobject_class,
ARG_SYNCHRONOUS,
g_param_spec_boolean ("synchronous",
"Synchronous",
"When enabled, runs "
"the X display in synchronous mode. (used only for debugging)",
FALSE,
G_PARAM_READWRITE));
/* TOGO */
g_object_class_install_property (gobject_class,
ARG_SIGNAL_HANDOFFS,
g_param_spec_boolean ("signal-handoffs",
"Signal handoffs",
"Send a signal before unreffing the buffer, forces YUV, no GL output",
FALSE,
G_PARAM_READWRITE));
gst_cltrimagesink_signals[SIGNAL_HANDOFF]
= g_signal_new ("handoff",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstCltrimageSinkClass, handoff),
NULL,
NULL,
gst_marshal_VOID__POINTER_OBJECT,
G_TYPE_NONE,
2,
GST_TYPE_BUFFER,
GST_TYPE_PAD);
gst_cltrimagesink_signals[SIGNAL_BUFALLOC] =
g_signal_new ("bufferalloc",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstCltrimageSinkClass, bufferalloc),
NULL,
NULL,
gst_marshal_VOID__POINTER_OBJECT,
G_TYPE_NONE, 2,
GST_TYPE_BUFFER, GST_TYPE_PAD);
gobject_class->finalize = gst_cltrimagesink_finalize;
gobject_class->set_property = gst_cltrimagesink_set_property;
gobject_class->get_property = gst_cltrimagesink_get_property;
gstelement_class->change_state = gst_cltrimagesink_change_state;
}
/* ============================================================= */
/* */
/* Public Methods */
/* */
/* ============================================================= */
/* =========================================== */
/* */
/* Object typing & Creation */
/* */
/* =========================================== */
GType
gst_cltrimagesink_get_type (void)
{
static GType cltrimagesink_type = 0;
if (!cltrimagesink_type)
{
static const GTypeInfo cltrimagesink_info =
{
sizeof (GstCltrimageSinkClass),
gst_cltrimagesink_base_init,
NULL,
(GClassInitFunc) gst_cltrimagesink_class_init,
NULL,
NULL,
sizeof (GstCltrimageSink),
0,
(GInstanceInitFunc) gst_cltrimagesink_init,
};
cltrimagesink_type
= g_type_register_static (GST_TYPE_VIDEOSINK,
"GstCltrimageSink",
&cltrimagesink_info,
0);
}
return cltrimagesink_type;
}
static gboolean
plugin_init (GstPlugin *plugin)
{
/* Loading the library containing GstVideoSink, our parent object */
if (!gst_library_load ("gstvideo"))
return FALSE;
if (!gst_element_register (plugin,
"cltrimagesink",
GST_RANK_SECONDARY,
GST_TYPE_CLTRIMAGESINK))
return FALSE;
GST_DEBUG_CATEGORY_INIT (gst_debug_cltrimagesink,
"cltrimagesink",
0,
"cltrimagesink element");
return TRUE;
}
#define GST_LICENSE "LGPL"
#define GST_PACKAGE "GStreamer"
#define GST_ORIGIN "http://o-hand.com"
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"cltrimagesink",
"Clutter video output plugin based on OpenGL 1.2 calls",
plugin_init,
VERSION,
GST_LICENSE,
GST_PACKAGE,
GST_ORIGIN)

File diff suppressed because it is too large Load diff

View file

@ -1,122 +0,0 @@
/* GStreamer
* Copyright (C) <2005> Julien Moutte <julien@moutte.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_CLUTTERIMAGESINK_H__
#define __GST_CLUTTERIMAGESINK_H__
#include <gst/video/gstvideosink.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <string.h>
#include <math.h>
G_BEGIN_DECLS
#define GST_TYPE_CLUTTERIMAGESINK \
(gst_clutterimagesink_get_type())
#define GST_CLUTTERIMAGESINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CLUTTERIMAGESINK, GstClutterImageSink))
#define GST_CLUTTERIMAGESINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CLUTTERIMAGESINK, GstClutterImageSink))
#define GST_IS_CLUTTERIMAGESINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CLUTTERIMAGESINK))
#define GST_IS_CLUTTERIMAGESINK_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CLUTTERIMAGESINK))
typedef struct _GstClutterContext GstClutterContext;
typedef struct _GstXWindow GstXWindow;
typedef struct _GstClutterImageBuffer GstClutterImageBuffer;
typedef struct _GstClutterImageBufferClass GstClutterImageBufferClass;
typedef struct _GstClutterImageSink GstClutterImageSink;
typedef struct _GstClutterImageSinkClass GstClutterImageSinkClass;
struct _GstClutterContext
{
Display *disp;
Screen *screen;
gint screen_num;
gint width, height;
gint widthmm, heightmm;
GValue *par; /* calculated pixel aspect ratio */
GstCaps *caps;
};
struct _GstClutterImageBuffer
{
GstBuffer buffer;
/* Reference to the clutterimagesink we belong to */
GstClutterImageSink *clutterimagesink;
GdkPixbuf *clutterimage; /* FIXME: Rename */
gint width, height;
size_t size;
};
struct _GstClutterImageSink
{
/* Our element stuff */
GstVideoSink videosink;
char *display_name;
GstClutterContext *context;
GstClutterImageBuffer *clutterimage;
GstClutterImageBuffer *cur_image;
GThread *event_thread;
gboolean running;
/* Framerate numerator and denominator */
gint fps_n;
gint fps_d;
/* object-set pixel aspect ratio */
GValue *par;
GMutex *x_lock; /* FIXME: rename */
GMutex *flow_lock;
GMutex *pool_lock;
GSList *buffer_pool;
ClutterVideoTexture *video_texture;
gboolean synchronous;
gboolean keep_aspect;
};
struct _GstClutterImageSinkClass {
GstVideoSinkClass parent_class;
};
GType gst_clutterimagesink_get_type(void);
G_END_DECLS
#endif /* __GST_CLUTTERIMAGESINK_H__ */

View file

@ -9,13 +9,13 @@ EXTRA_DIST = gtk-clutter.pc.in
CLEANFILES = $(pcfiles)
INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ $(GST_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir)
INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ $(GTK_CFLAGS) -I$(top_srcdir)
lib_LTLIBRARIES = libgtkclutter-@CLUTTER_MAJORMINOR@.la
libgtkclutter_@CLUTTER_MAJORMINOR@_la_SOURCES = gtk-clutter.c
libgtkclutter_@CLUTTER_MAJORMINOR@_la_LIBADD = \
@CLUTTER_LIBS@ $(GST_LIBS) $(GTK_LIBS)
@CLUTTER_LIBS@ $(GTK_LIBS)
libgtkclutter_@CLUTTER_MAJORMINOR@_la_LDFLAGS = @CLUTTER_LT_LDFLAGS@
gtkclutterheadersdir = \
@ -27,8 +27,7 @@ noinst_PROGRAMS = gtk-clutter-test
gtk_clutter_test_SOURCES = gtk-clutter-test.c
gtk_clutter_test_LDADD = libgtkclutter-@CLUTTER_MAJORMINOR@.la \
$(CLUTTER_LIBS) \
$(GST_LIBS) \
$(GTK_LIBS) \
$(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la
gtk_clutter_test_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS)
gtk_clutter_test_CFLAGS = $(CLUTTER_CFLAGS) $(GTK_CFLAGS)