mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 09:30:45 -05:00
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:
parent
f907bcee1e
commit
458b4b47a7
25
ChangeLog
25
ChangeLog
@ -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
6
README
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
|
11
configure.ac
11
configure.ac
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 |
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
@ -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__ */
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user