diff --git a/ChangeLog b/ChangeLog index d262cf72b..95fffa0d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2005-04-26 mallum,,, + + * clutter/Makefile.am: + * clutter/cltr-core.c: (cltr_init): + * clutter/cltr-events.c: (cltr_events_init), (cltr_main_loop): + * clutter/cltr-photo-grid.c: + * clutter/cltr-private.h: + * clutter/cltr-scratch.c: (cltr_scratch_handle_xevent), + (cltr_scratch_paint): + * clutter/cltr-texture.c: (cltr_texture_render_to_gl_quad), + (init_tiles), (cltr_texture_unrealize), (cltr_texture_realize), + (cltr_texture_new), (cltr_texture_no_tile_new), + (cltr_texture_get_pixbuf): + * clutter/cltr-texture.h: + * clutter/cltr-video.c: + * clutter/cltr-video.h: + * clutter/cltr-widget.c: (cltr_widget_queue_paint): + * clutter/cltr.h: + * examples/Makefile.am: + * examples/player.c: + * gst/cltrimagesink.c: (gst_cltrimagesink_fixate), + (gst_cltrimagesink_getcaps), (gst_cltrimagesink_sink_link), + (gst_cltrimagesink_change_state), (gst_cltrimagesink_chain), + (gst_cltrimagesink_set_property), (gst_cltrimagesink_get_property), + (gst_cltrimagesink_finalize), (gst_cltrimagesink_class_init): + * gst/cltrimagesink.h: + Initial go at very hacky gst video widget + 2005-04-22 mallum,,, * clutter/Makefile.am: diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 3871a94c9..3360b8c08 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -7,6 +7,7 @@ source_h = pixbuf.h util.h fonts.h \ cltr-widget.h \ cltr-window.h \ cltr-photo-grid.h \ + cltr-video.h \ cltr-list.h \ cltr-overlay.h \ cltr-button.h \ @@ -20,16 +21,17 @@ source_c = pixbuf.c util.c fonts.c \ cltr-events.c \ cltr-window.c \ cltr-photo-grid.c \ + cltr-video.c \ cltr-list.c \ cltr-overlay.c \ cltr-button.c \ cltr-scratch.c -AM_CFLAGS = @GCC_FLAGS@ @CLTR_CFLAGS@ +AM_CFLAGS = @GCC_FLAGS@ @CLTR_CFLAGS@ $(GST_CFLAGS) $(GCONF_CFLAGS) lib_LTLIBRARIES = libclutter.la libclutter_la_SOURCES = $(source_c) $(source_h) -libclutter_la_LIBADD = @CLTR_LIBS@ +libclutter_la_LIBADD = @CLTR_LIBS@ $(GST_LIBS) $(GCONF_LIBS) # http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 # current : revision : age diff --git a/clutter/cltr-core.c b/clutter/cltr-core.c index cfcbcbdb4..7938e16d6 100644 --- a/clutter/cltr-core.c +++ b/clutter/cltr-core.c @@ -34,6 +34,8 @@ cltr_init(int *argc, char ***argv) XVisualInfo *vinfo; + gst_init (argc, argv); + if (!g_thread_supported ()) g_thread_init (NULL); // XInitThreads (); diff --git a/clutter/cltr-events.c b/clutter/cltr-events.c index 9e864b89b..9b089c5e0 100644 --- a/clutter/cltr-events.c +++ b/clutter/cltr-events.c @@ -137,7 +137,7 @@ cltr_events_init() g_source_attach (source, gmain_context); g_source_unref (source); - ctx->internal_event_q = g_queue_new(); + ctx->internal_event_q = g_async_queue_new(); } void @@ -155,12 +155,12 @@ cltr_main_loop() while (TRUE) { - if (!g_queue_is_empty (ctx->internal_event_q)) + if (g_async_queue_length (ctx->internal_event_q)) { CltrWindow *win = CLTR_WINDOW(ctx->window); /* Empty the queue */ - while (g_queue_pop_head(ctx->internal_event_q) != NULL) ; + while (g_async_queue_try_pop(ctx->internal_event_q) != NULL) ; /* Repaint everything visible from window down - URG. * GL workings make it difficult to paint single part with diff --git a/clutter/cltr-photo-grid.c b/clutter/cltr-photo-grid.c index 0f2569815..0a5d50536 100644 --- a/clutter/cltr-photo-grid.c +++ b/clutter/cltr-photo-grid.c @@ -22,7 +22,7 @@ */ -#define FPS_TO_TIMEOUT(t) (1000/(t)) + struct CltrPhotoGridCell { diff --git a/clutter/cltr-private.h b/clutter/cltr-private.h index bc6ae40f3..a8ffec25c 100644 --- a/clutter/cltr-private.h +++ b/clutter/cltr-private.h @@ -65,11 +65,13 @@ struct ClutterMainContext GLXContext gl_context; CltrWidget *window; - GQueue *internal_event_q; + GAsyncQueue *internal_event_q; }; ClutterMainContext CltrCntx; #define CLTR_CONTEXT() &CltrCntx +#define FPS_TO_TIMEOUT(t) (1000/(t)) + #endif diff --git a/clutter/cltr-scratch.c b/clutter/cltr-scratch.c index d0ead1c5a..2b611b06f 100644 --- a/clutter/cltr-scratch.c +++ b/clutter/cltr-scratch.c @@ -67,7 +67,7 @@ cltr_scratch_handle_xevent (CltrWidget *widget, XEvent *xev) } static void -cltr_scratch_paint(CltrWidget *widget) +cltr_scratch_paint_old(CltrWidget *widget) { CltrScratch *scratch = CLTR_SCRATCH(widget); @@ -120,8 +120,10 @@ cltr_scratch_paint(CltrWidget *widget) static void -cltr_scratch_paint_old(CltrWidget *widget) +cltr_scratch_paint(CltrWidget *widget) { + CltrScratch *scratch = CLTR_SCRATCH(widget); + glPushMatrix(); CLTR_MARK(); @@ -136,6 +138,15 @@ cltr_scratch_paint_old(CltrWidget *widget) widget->x + widget->width, widget->y + widget->height); + glEnable(GL_TEXTURE_2D); + + cltr_texture_render_to_gl_quad(scratch->tex, + widget->x, + widget->y, + widget->x + widget->width , + widget->y + widget->height); + + glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); diff --git a/clutter/cltr-texture.c b/clutter/cltr-texture.c index 3b5525cc7..ef9d39c80 100644 --- a/clutter/cltr-texture.c +++ b/clutter/cltr-texture.c @@ -32,8 +32,8 @@ cltr_texture_render_to_gl_quad(CltrTexture *texture, int x2, int y2) { - int qx1, qx2, qy1, qy2; - int qwidth, qheight; + int qx1 = 0, qx2 = 0, qy1 = 0, qy2 = 0; + int qwidth = 0, qheight = 0; int x, y, i =0, lastx = 0, lasty = 0; float tx, ty; @@ -43,6 +43,29 @@ cltr_texture_render_to_gl_quad(CltrTexture *texture, if (texture->tiles == NULL) cltr_texture_realize(texture); + if (!texture->tiled) + { + glBindTexture(GL_TEXTURE_2D, texture->tiles[0]); + + tx = (float) texture->pixb->width / texture->width; + ty = (float) texture->pixb->height / texture->height; + + qx1 = x1; + qx2 = x2; + + qy1 = y1; + qy2 = y2; + + glBegin (GL_QUADS); + glTexCoord2f (tx, ty); glVertex2i (qx2, qy2); + glTexCoord2f (0, ty); glVertex2i (qx1, qy2); + glTexCoord2f (0, 0); glVertex2i (qx1, qy1); + glTexCoord2f (tx, 0); glVertex2i (qx2, qy1); + glEnd (); + + return; + } + for (x=0; x < texture->n_x_tiles; x++) { lasty = 0; @@ -239,10 +262,15 @@ cltr_texture_unrealize(CltrTexture *texture) if (texture->tiles == NULL) return; - glDeleteTextures(texture->n_x_tiles * texture->n_y_tiles, texture->tiles); + if (!texture->tiled) + glDeleteTextures(1, texture->tiles); + else + glDeleteTextures(texture->n_x_tiles * texture->n_y_tiles, texture->tiles); + g_free(texture->tiles); texture->tiles = NULL; + } void @@ -250,8 +278,41 @@ cltr_texture_realize(CltrTexture *texture) { int x, y, i = 0; - texture->tiles = g_new (GLuint, texture->n_x_tiles * texture->n_y_tiles); - glGenTextures (texture->n_x_tiles * texture->n_y_tiles, texture->tiles); + if (!texture->tiled) + { + if (!texture->tiles) + { + texture->tiles = g_new (GLuint, 1); + glGenTextures (1, texture->tiles); + } + + glBindTexture(GL_TEXTURE_2D, texture->tiles[0]); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + + glTexImage2D(GL_TEXTURE_2D, 0, /*GL_COMPRESSED_RGBA_ARB*/ GL_RGBA, + texture->width, + texture->height, + 0, GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8, + NULL); + + CLTR_GLERR(); + + cltr_texture_sync_pixbuf(texture); + + return; + } + + if (!texture->tiles) + { + texture->tiles = g_new (GLuint, texture->n_x_tiles * texture->n_y_tiles); + glGenTextures (texture->n_x_tiles * texture->n_y_tiles, texture->tiles); + } for (x=0; x < texture->n_x_tiles; x++) for (y=0; y < texture->n_y_tiles; y++) @@ -259,41 +320,40 @@ cltr_texture_realize(CltrTexture *texture) Pixbuf *pixtmp; int src_h, src_w; - - src_w = texture->tile_x_size[x]; src_h = texture->tile_y_size[y]; - + /* - CLTR_DBG("%i+%i, %ix%i to %ix%i, waste %ix%i", - texture->tile_x_position[x], - texture->tile_y_position[y], - texture->tile_x_size[x], - texture->tile_y_size[y], - texture->width, - texture->height, - texture->tile_x_waste[x], - texture->tile_y_waste[y]); + CLTR_DBG("%i+%i, %ix%i to %ix%i, waste %ix%i", + texture->tile_x_position[x], + texture->tile_y_position[y], + texture->tile_x_size[x], + texture->tile_y_size[y], + texture->width, + texture->height, + texture->tile_x_waste[x], + texture->tile_y_waste[y]); */ - + /* Only break the pixbuf up if we have multiple tiles */ - if (texture->n_x_tiles > 1 && texture->n_y_tiles >1) - { - pixtmp = pixbuf_new(texture->tile_x_size[x], - texture->tile_y_size[y]); - - pixbuf_copy(texture->pixb, - pixtmp, - texture->tile_x_position[x], - texture->tile_y_position[y], - texture->tile_x_size[x], - texture->tile_y_size[y], - 0,0); - } - else pixtmp = texture->pixb; - + /* if (texture->n_x_tiles > 1 && texture->n_y_tiles >1) */ + { + pixtmp = pixbuf_new(texture->tile_x_size[x], + texture->tile_y_size[y]); + + pixbuf_copy(texture->pixb, + pixtmp, + texture->tile_x_position[x], + texture->tile_y_position[y], + texture->tile_x_size[x], + texture->tile_y_size[y], + 0,0); + } + /* else pixtmp = texture->pixb; */ + + glBindTexture(GL_TEXTURE_2D, texture->tiles[i]); - + CLTR_GLERR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); @@ -311,12 +371,16 @@ cltr_texture_realize(CltrTexture *texture) CLTR_GLERR(); - if (pixtmp != texture->pixb) - pixbuf_unref(pixtmp); - + CLTR_DBG("pixtmp is %ix%i texture %ix%i\n", + pixtmp->width, pixtmp->height, + texture->width, texture->height); + + pixbuf_unref(pixtmp); + i++; } + } CltrTexture* @@ -324,24 +388,55 @@ cltr_texture_new(Pixbuf *pixb) { CltrTexture *texture; - CLTR_MARK(); texture = g_malloc0(sizeof(CltrTexture)); texture->width = pixb->width; texture->height = pixb->height; + texture->tiled = TRUE; /* maybe we should copy the pixbuf - a change to refed one would explode */ texture->pixb = pixb; + texture->mutex = g_mutex_new(); pixbuf_ref(pixb); + + init_tiles (texture); return texture; } +CltrTexture* +cltr_texture_no_tile_new(Pixbuf *pixb) +{ + CltrTexture *texture; + + CLTR_MARK(); + + texture = g_malloc0(sizeof(CltrTexture)); + + texture->tiled = FALSE; + texture->width = next_p2(pixb->width); + texture->height = next_p2(pixb->height); + + if (!can_create (texture->width, texture->height)) + { + free(texture); + return NULL; + } + + texture->pixb = pixb; + texture->mutex = g_mutex_new(); + + pixbuf_ref(pixb); + + return texture; +} + + Pixbuf* cltr_texture_get_pixbuf(CltrTexture* texture) { @@ -349,7 +444,62 @@ cltr_texture_get_pixbuf(CltrTexture* texture) } void -cltr_texture_resync_pixbuf(CltrTexture* texture) +cltr_texture_lock(CltrTexture* texture) { - cltr_texture_unrealize(texture); + g_mutex_lock(texture->mutex); +} + +void +cltr_texture_unlock(CltrTexture* texture) +{ + g_mutex_unlock(texture->mutex); +} + +void +cltr_texture_sync_pixbuf(CltrTexture* texture) +{ + if (texture->tiled) + { + cltr_texture_realize(texture); + } + else + { + glBindTexture(GL_TEXTURE_2D, texture->tiles[0]); + + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, + texture->pixb->width, + texture->pixb->height, + GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, + texture->pixb->data); + } +} + + +/* + * This is a nasty hack to work round me not figuring out + * how to get RGBA data out of gstreamer in a format clutters + * GL setup can handle :( + * + * The good side is it probably speeds video playback up by + * avoiding copys of frame data. + */ +void +cltr_texture_force_rgb_data(CltrTexture *texture, + int width, + int height, + int *data) +{ + if (texture->tiled) + return; + + if (!texture->tiles) + cltr_texture_realize(texture); + + glBindTexture(GL_TEXTURE_2D, texture->tiles[0]); + + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, + width, + height, + GL_RGB, GL_UNSIGNED_BYTE, + data); } diff --git a/clutter/cltr-texture.h b/clutter/cltr-texture.h index 8a8b0846b..678d28f2c 100644 --- a/clutter/cltr-texture.h +++ b/clutter/cltr-texture.h @@ -3,7 +3,7 @@ #include "cltr.h" -typedef struct CltrTexture CltrTexture; + struct CltrTexture { @@ -11,12 +11,16 @@ struct CltrTexture int width, height; + gboolean tiled; + int n_x_tiles, n_y_tiles; int *tile_x_position, *tile_x_size, *tile_x_waste; int *tile_y_position, *tile_y_size, *tile_y_waste; GLuint *tiles; + GMutex *mutex; + gint refcnt; }; @@ -24,6 +28,9 @@ struct CltrTexture CltrTexture* cltr_texture_new(Pixbuf *pixb); +CltrTexture* +cltr_texture_no_tile_new(Pixbuf *pixb); + void cltr_texture_unrealize(CltrTexture *texture); @@ -41,7 +48,19 @@ Pixbuf* cltr_texture_get_pixbuf(CltrTexture* texture); void -cltr_texture_resync_pixbuf(CltrTexture* texture); +cltr_texture_lock(CltrTexture* texture); + +void +cltr_texture_unlock(CltrTexture* texture); + +void +cltr_texture_sync_pixbuf(CltrTexture* texture); + +void +cltr_texture_force_rgb_data(CltrTexture *texture, + int width, + int height, + int *data); #endif diff --git a/clutter/cltr-video.c b/clutter/cltr-video.c new file mode 100644 index 000000000..2c099d763 --- /dev/null +++ b/clutter/cltr-video.c @@ -0,0 +1,425 @@ +#include "cltr-video.h" +#include "cltr-private.h" + +struct CltrVideo +{ + CltrWidget widget; + + GstPlay *play; + GstElement *data_src, *video_sink, *audio_sink, *vis_element; + + GAsyncQueue *queue; + + int video_width, video_height; + CltrTexture *frame_texture; +}; + + + +static void +cltr_video_show(CltrWidget *widget); + +static gboolean +cltr_video_handle_xevent (CltrWidget *widget, XEvent *xev); + +static void +cltr_video_paint(CltrWidget *widget); + + + +static gint64 length = 0; /* to go */ + +static void +cltr_video_print_tag (const GstTagList *list, + const gchar *tag, + gpointer unused) +{ + gint i, count; + + count = gst_tag_list_get_tag_size (list, tag); + + for (i = 0; i < count; i++) { + gchar *str; + + if (gst_tag_get_type (tag) == G_TYPE_STRING) { + if (!gst_tag_list_get_string_index (list, tag, i, &str)) + g_assert_not_reached (); + } else { + str = + g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i)); + } + + if (i == 0) { + g_print ("%15s: %s\n", gst_tag_get_nick (tag), str); + } else { + g_print (" : %s\n", str); + } + + g_free (str); + } +} + +static void +cltr_video_got_found_tag (GstPlay *play, + GstElement *source, + GstTagList *tag_list, + CltrVideo *video) +{ + CltrVideoSignal *signal; + + signal = g_new0 (CltrVideoSignal, 1); + signal->signal_id = CLTR_VIDEO_ASYNC_FOUND_TAG; + signal->signal_data.found_tag.source = source; + signal->signal_data.found_tag.tag_list = gst_tag_list_copy (tag_list); + + g_async_queue_push (video->queue, signal); + + /* gst_tag_list_foreach (tag_list, cltr_video_print_tag, NULL); */ +} + +static void +cltr_video_got_time_tick (GstPlay *play, + gint64 time_nanos, + CltrVideo *video) +{ + CltrVideoSignal *signal; + + /* + signal = g_new0 (CltrVideoSignal, 1); + signal->signal_id = CLTR_VIDEO_ASYNC_FOUND_TAG; + signal->signal_data.found_tag.source = source; + signal->signal_data.found_tag.tag_list = gst_tag_list_copy (tag_list); + + g_async_queue_push (video->queue, signal); + */ + + g_print ("time tick %f\n", time_nanos / (float) GST_SECOND); +} + +static void +cltr_video_got_stream_length (GstPlay *play, + gint64 length_nanos, + CltrVideo *video) +{ + /* + CltrVideoSignal *signal; + + signal = g_new0 (CltrVideoSignal, 1); + + signal->signal_id = CLTR_VIDEO_ASYNC_VIDEO_SIZE; + signal->signal_data.video_size.width = width; + signal->signal_data.video_size.height = height; + + g_async_queue_push (video->queue, signal); + */ + CLTR_DBG ("got length %" G_GUINT64_FORMAT "\n", length_nanos); + length = length_nanos; +} + +static void +cltr_video_got_video_size (GstPlay *play, + gint width, + gint height, + CltrVideo *video) +{ + CltrVideoSignal *signal; + + signal = g_new0 (CltrVideoSignal, 1); + + signal->signal_id = CLTR_VIDEO_ASYNC_VIDEO_SIZE; + signal->signal_data.video_size.width = width; + signal->signal_data.video_size.height = height; + + g_async_queue_push (video->queue, signal); +} + +static void +cltr_video_got_eos (GstPlay* play, CltrVideo *video) +{ + CLTR_DBG ("End Of Stream\n"); + + CltrVideoSignal *signal; + + signal = g_new0 (CltrVideoSignal, 1); + + signal->signal_id = CLTR_VIDEO_ASYNC_EOS; + + g_async_queue_push (video->queue, signal); + + gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); +} + +static gboolean +cltr_video_seek_timer (GstPlay * play) +{ + gst_play_seek_to_time (play, length / 2); + return FALSE; +} + +static void +caps_set (GObject *obj, + GParamSpec *pspec, + CltrVideo *video) +{ + GstPad *pad = GST_PAD (obj); + GstStructure *s; + + if (!GST_PAD_CAPS (pad)) + return; + + s = gst_caps_get_structure (GST_PAD_CAPS (pad), 0); + + if (s) { + + + const GValue *par; + + if (!(gst_structure_get_double (s, "framerate", &bvw->priv->video_fps) && + gst_structure_get_int (s, "width", &bvw->priv->video_width) && + gst_structure_get_int (s, "height", &bvw->priv->video_height))) + return; + if ((par = gst_structure_get_value (s, + "pixel-aspect-ratio"))) { + gint num = gst_value_get_fraction_numerator (par), + den = gst_value_get_fraction_denominator (par); + + if (num > den) + bvw->priv->video_width *= (gfloat) num / den; + else + bvw->priv->video_height *= (gfloat) den / num; + } + + got_video_size (bvw->priv->play, bvw->priv->video_width, + bvw->priv->video_height, bvw); + } + */ + /* and disable ourselves */ + //g_signal_handlers_disconnect_by_func (pad, caps_set, bvw); +} + + +CltrWidget* +cltr_video_new(int width, int height) +{ + CltrVideo *video; + GError *error = NULL; + + video = g_malloc0(sizeof(CltrVideo)); + + video->widget.width = width; + video->widget.height = height; + + video->widget.show = cltr_video_show; + video->widget.paint = cltr_video_paint; + + video->widget.xevent_handler = cltr_video_handle_xevent; + + /* Creating the GstPlay object */ + + video->play = gst_play_new (&error); + + if (error) + { + g_print ("Error: could not create play object:\n%s\n", error->message); + g_error_free (error); + return NULL; + } + + /* Getting default audio and video plugins from GConf */ + video->vis_element = gst_element_factory_make ("goom", "vis_element"); + video->data_src = gst_element_factory_make ("gnomevfssrc", "source"); + + video->audio_sink = gst_gconf_get_default_audio_sink (); + + if (!GST_IS_ELEMENT (video->audio_sink)) + g_error ("Could not get default audio sink from GConf"); + + video->video_sink = gst_element_factory_make ("cltrimagesink", "cltr-output"); + + if (!GST_IS_ELEMENT (video->video_sink)) + g_error ("Could not get clutter video sink"); + + video->queue = g_async_queue_new (); + + gst_element_set(video->video_sink, "queue", video->queue, NULL); + + /* Let's send them to GstPlay object */ + + if (!gst_play_set_audio_sink (video->play, video->audio_sink)) + g_warning ("Could not set audio sink"); + if (!gst_play_set_video_sink (video->play, video->video_sink)) + g_warning ("Could not set video sink"); + if (!gst_play_set_data_src (video->play, video->data_src)) + g_warning ("Could not set data src"); + if (!gst_play_set_visualization (video->play, video->vis_element)) + g_warning ("Could not set visualisation"); + + /* Setting location we want to play */ + + /* Uncomment that line to get an XML dump of the pipeline */ + /* gst_xml_write_file (GST_ELEMENT (play), stdout); */ + + g_signal_connect (G_OBJECT (video->play), "time_tick", + G_CALLBACK (cltr_video_got_time_tick), video); + g_signal_connect (G_OBJECT (video->play), "stream_length", + G_CALLBACK (cltr_video_got_stream_length), video); + g_signal_connect (G_OBJECT (video->play), "have_video_size", + G_CALLBACK (cltr_video_got_video_size), video); + g_signal_connect (G_OBJECT (video->play), "found_tag", + G_CALLBACK (cltr_video_got_found_tag), video); + g_signal_connect (G_OBJECT (video->play), "error", + G_CALLBACK (gst_element_default_error), NULL); + g_signal_connect (G_OBJECT (video->play), + "eos", G_CALLBACK (cltr_video_got_eos), video); + + g_signal_connect (G_OBJECT (video->video_sink), "notify::caps", + G_CALLBACK (caps_set), video); + + + /* + g_object_set (G_OBJECT (video->play), "volume", + (gdouble) (1. * 0 / 100), NULL); + */ + + /* gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); */ + + return CLTR_WIDGET(video); +} + + +static gboolean +cltr_video_idler (CltrVideo *video) +{ + gint queue_length; + CltrVideoSignal *signal; + + signal = g_async_queue_try_pop (video->queue); + + if (!signal) + return TRUE; + + switch (signal->signal_id) + { + case CLTR_VIDEO_ASYNC_TEXTURE: + video->frame_texture = signal->signal_data.texture.ref; + + /* + * we can actually grab the width and height from + * the textures pixbuf. + */ + + cltr_widget_queue_paint(CLTR_WIDGET(video)); + break; + case CLTR_VIDEO_ASYNC_VIDEO_SIZE: + video->video_width = signal->signal_data.video_size.width; + video->video_height = signal->signal_data.video_size.height; + break; + case CLTR_VIDEO_ASYNC_ERROR: + break; + case CLTR_VIDEO_ASYNC_FOUND_TAG: + break; + case CLTR_VIDEO_ASYNC_NOTIFY_STREAMINFO: + break; + case CLTR_VIDEO_ASYNC_EOS: + break; + case CLTR_VIDEO_ASYNC_BUFFERING: + break; + case CLTR_VIDEO_ASYNC_REDIRECT: + break; + } + + g_free (signal); + + return TRUE; +} + +gboolean +cltr_video_set_source(CltrVideo *video, char *location) +{ + if (!gst_play_set_location (video->play, location)) + return FALSE; + + return TRUE; +} + +void +cltr_video_play(CltrVideo *video) +{ + /* Change state to PLAYING */ + if (gst_element_set_state (GST_ELEMENT (video->play), + GST_STATE_PLAYING) == GST_STATE_FAILURE) + g_error ("Could not set state to PLAYING"); + + g_timeout_add(FPS_TO_TIMEOUT(20), (GSourceFunc) cltr_video_idler, video); +} + +void +cltr_video_pause(CltrVideo *video) +{ + if (gst_element_set_state (GST_ELEMENT (video->play), + GST_STATE_PAUSED) == GST_STATE_FAILURE) + g_error ("Could not set state to PAUSED"); +} + + +static void +cltr_video_show(CltrWidget *widget) +{ + return; +} + +static void +cltr_video_hide(CltrWidget *widget) +{ + return; +} + +static gboolean +cltr_video_handle_xevent (CltrWidget *widget, XEvent *xev) +{ + CLTR_DBG("X Event"); + + return False; +} + +static void +cltr_video_paint(CltrWidget *widget) +{ + CltrVideo *video = CLTR_VIDEO(widget); + + glPushMatrix(); + + if (video->frame_texture + && video->video_height + && video->video_width) + { + int dis_x, dis_y, dis_height, dis_width; + + if (video->video_width > video->video_height) + { + dis_width = widget->width; + dis_height = ( video->video_height * widget->width ) + / video->video_width; + dis_y = (widget->height - dis_height)/2; + dis_x = 0; + } + + glColor4f(1.0, 1.0, 1.0, 1.0); + + glEnable(GL_TEXTURE_2D); + + cltr_texture_lock(video->frame_texture); + + cltr_texture_render_to_gl_quad(video->frame_texture, + dis_x, + dis_y, + dis_x + dis_width, + dis_y + dis_height); + + cltr_texture_unlock(video->frame_texture); + + glDisable(GL_TEXTURE_2D); + } + + glPopMatrix(); +} diff --git a/clutter/cltr-video.h b/clutter/cltr-video.h new file mode 100644 index 000000000..c5da08eba --- /dev/null +++ b/clutter/cltr-video.h @@ -0,0 +1,73 @@ +#ifndef _HAVE_CLTR_VIDEO_H +#define _HAVE_CLTR_VIDEO_H + +#include "cltr.h" + +#include +#include + +typedef struct CltrVideo CltrVideo; + +/* Signals - cltrimagesink needs to deliver texture signals :/ */ + +enum { + CLTR_VIDEO_ASYNC_TEXTURE, + CLTR_VIDEO_ASYNC_VIDEO_SIZE, + CLTR_VIDEO_ASYNC_ERROR, + CLTR_VIDEO_ASYNC_FOUND_TAG, + CLTR_VIDEO_ASYNC_NOTIFY_STREAMINFO, + CLTR_VIDEO_ASYNC_EOS, + CLTR_VIDEO_ASYNC_BUFFERING, + CLTR_VIDEO_ASYNC_REDIRECT +}; + +typedef struct CltrVideoSignal +{ + gint signal_id; + union + { + struct + { + gint width; + gint height; + } video_size; + struct + { + GstElement *element; + GError *error; + char *debug_message; + } error; + struct + { + GstElement *source; + GstTagList *tag_list; + } found_tag; + struct + { + gint percent; + } buffering; + struct + { + gchar *new_location; + } redirect; + struct + { + CltrTexture *ref; + } texture; + } signal_data; +} +CltrVideoSignal; + +#define CLTR_VIDEO(w) ((CltrVideo*)(w)) + +CltrWidget* +cltr_video_new(int width, int height); + +gboolean +cltr_video_set_source(CltrVideo *video, char *location); + +void +cltr_video_play(CltrVideo *video); + + +#endif diff --git a/clutter/cltr-widget.c b/clutter/cltr-widget.c index 4ffa4a4a4..e21c24380 100644 --- a/clutter/cltr-widget.c +++ b/clutter/cltr-widget.c @@ -101,7 +101,7 @@ cltr_widget_queue_paint(CltrWidget *widget) { ClutterMainContext *ctx = CLTR_CONTEXT(); - g_queue_push_head (ctx->internal_event_q, (gpointer)widget); + g_async_queue_push (ctx->internal_event_q, (gpointer)widget); } gboolean diff --git a/clutter/cltr.h b/clutter/cltr.h index 601fd043a..51db92b9a 100644 --- a/clutter/cltr.h +++ b/clutter/cltr.h @@ -16,6 +16,8 @@ #include +#include + #include "pixbuf.h" #include "fonts.h" @@ -34,6 +36,8 @@ typedef struct CltrRect } CltrRect; +typedef struct CltrTexture CltrTexture; + #define cltr_rect_x1(r) ((r).x) #define cltr_rect_y1(r) ((r).y) #define cltr_rect_x2(r) ((r).x + (r).width) @@ -52,5 +56,6 @@ CltrRect; #include "cltr-overlay.h" #include "cltr-button.h" #include "cltr-photo-grid.h" +#include "cltr-video.h" #endif diff --git a/examples/Makefile.am b/examples/Makefile.am index 100271882..256fd1950 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,15 +1,19 @@ noinst_PROGRAMS = scratch photos player scratch_SOURCES = scratch.c -scratch_CFLAGS = $(CLTR_CFLAGS) +scratch_CFLAGS = $(CLTR_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS) scratch_LDFLAGS = \ $(CLTR_LIBS) \ + $(GST_LIBS) \ + $(GCONF_LIBS) \ $(top_builddir)/clutter/libclutter.la photos_SOURCES = photos.c -photos_CFLAGS = $(CLTR_CFLAGS) +photos_CFLAGS = $(CLTR_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS) photos_LDFLAGS = \ $(CLTR_LIBS) \ + $(GST_LIBS) \ + $(GCONF_LIBS) \ $(top_builddir)/clutter/libclutter.la player_SOURCES = player.c diff --git a/examples/player.c b/examples/player.c index 9cdd96738..41d77726f 100644 --- a/examples/player.c +++ b/examples/player.c @@ -19,90 +19,11 @@ #include -#include -#include - -static GMainLoop *loop = NULL; -static gint64 length = 0; - -static void -print_tag (const GstTagList * list, const gchar * tag, gpointer unused) -{ - gint i, count; - - count = gst_tag_list_get_tag_size (list, tag); - - for (i = 0; i < count; i++) { - gchar *str; - - if (gst_tag_get_type (tag) == G_TYPE_STRING) { - if (!gst_tag_list_get_string_index (list, tag, i, &str)) - g_assert_not_reached (); - } else { - str = - g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i)); - } - - if (i == 0) { - g_print ("%15s: %s\n", gst_tag_get_nick (tag), str); - } else { - g_print (" : %s\n", str); - } - - g_free (str); - } -} - -static void -got_found_tag (GstPlay * play, GstElement * source, GstTagList * tag_list) -{ - gst_tag_list_foreach (tag_list, print_tag, NULL); -} - -static void -got_time_tick (GstPlay * play, gint64 time_nanos) -{ - g_print ("time tick %f\n", time_nanos / (float) GST_SECOND); -} - -static void -got_stream_length (GstPlay * play, gint64 length_nanos) -{ - g_print ("got length %" G_GUINT64_FORMAT "\n", length_nanos); - length = length_nanos; -} - -static void -got_video_size (GstPlay * play, gint width, gint height) -{ - g_print ("got video size %d, %d\n", width, height); -} - -static void -got_eos (GstPlay * play) -{ - g_print ("End Of Stream\n"); - g_main_loop_quit (loop); -} - -static gboolean -seek_timer (GstPlay * play) -{ - gst_play_seek_to_time (play, length / 2); - return FALSE; -} - int main (int argc, char *argv[]) { - GstPlay *play; - GstElement *data_src, *video_sink, *audio_sink, *vis_element; - GError *error = NULL; + CltrWidget *win, *video, *test; - CltrWidget *win; - - /* Initing GStreamer library */ - gst_init (&argc, &argv); cltr_init (&argc, &argv); if (argc != 2) { @@ -111,86 +32,22 @@ main (int argc, char *argv[]) } win = cltr_window_new(800, 600); + + video = cltr_video_new(800, 600); + + cltr_video_set_source(CLTR_VIDEO(video), argv[1]); + + cltr_widget_add_child(win, video, 0, 0); + + test = cltr_scratch_new(300, 300); + + cltr_widget_add_child(win, test, 100, 100); + cltr_widget_show_all(win); - loop = g_main_loop_new (NULL, FALSE); - - /* Creating the GstPlay object */ - play = gst_play_new (&error); - if (error) { - g_print ("Error: could not create play object:\n%s\n", error->message); - g_error_free (error); - return 1; - } - - /* Getting default audio and video plugins from GConf */ - vis_element = gst_element_factory_make ("goom", "vis_element"); - data_src = gst_element_factory_make ("gnomevfssrc", "source"); - - audio_sink = gst_gconf_get_default_audio_sink (); - if (!GST_IS_ELEMENT (audio_sink)) - g_error ("Could not get default audio sink from GConf"); - - /* - video_sink = gst_gconf_get_default_video_sink (); - if (!GST_IS_ELEMENT (video_sink)) - g_error ("Could not get default video sink from GConf"); - */ - - video_sink = gst_element_factory_make ("cltrimagesink", "cltr-output"); - - gst_element_set(video_sink, "widget", win, NULL); - - if (video_sink == NULL) - g_printf("sink NULL\n"); - - /* Let's send them to GstPlay object */ - if (!gst_play_set_audio_sink (play, audio_sink)) - g_warning ("Could not set audio sink"); - if (!gst_play_set_video_sink (play, video_sink)) - g_warning ("Could not set video sink"); - if (!gst_play_set_data_src (play, data_src)) - g_warning ("Could not set data src"); - if (!gst_play_set_visualization (play, vis_element)) - g_warning ("Could not set visualisation"); - - /* Setting location we want to play */ - if (!gst_play_set_location (play, argv[1])) - g_warning ("Could not set location"); - - /* Uncomment that line to get an XML dump of the pipeline */ - gst_xml_write_file (GST_ELEMENT (play), stdout); - - g_signal_connect (G_OBJECT (play), "time_tick", - G_CALLBACK (got_time_tick), NULL); - g_signal_connect (G_OBJECT (play), "stream_length", - G_CALLBACK (got_stream_length), NULL); - g_signal_connect (G_OBJECT (play), "have_video_size", - G_CALLBACK (got_video_size), NULL); - g_signal_connect (G_OBJECT (play), "found_tag", - G_CALLBACK (got_found_tag), NULL); - g_signal_connect (G_OBJECT (play), "error", - G_CALLBACK (gst_element_default_error), NULL); - g_signal_connect (G_OBJECT (play), "eos", G_CALLBACK (got_eos), NULL); - - /* Change state to PLAYING */ - if (gst_element_set_state (GST_ELEMENT (play), - GST_STATE_PLAYING) == GST_STATE_FAILURE) - g_error ("Could not set state to PLAYING"); - - g_timeout_add (20000, (GSourceFunc) seek_timer, play); - - + cltr_video_play(CLTR_VIDEO(video)); cltr_main_loop(); - // g_main_loop_run (loop); - - g_print ("setting pipeline to ready\n"); - - gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); - - /* unref - gst_object_unref (GST_OBJECT (play)); */ exit (0); } diff --git a/gst/cltrimagesink.c b/gst/cltrimagesink.c index 9d93d5e47..b86940ab9 100644 --- a/gst/cltrimagesink.c +++ b/gst/cltrimagesink.c @@ -30,7 +30,7 @@ /* Debugging category */ #include -GST_DEBUG_CATEGORY_STATIC (gst_debug_cltrimagesink); +GST_DEBUG_CATEGORY_STATIC (gst_debug_cltrimagesink); #define GST_CAT_DEFAULT gst_debug_cltrimagesink @@ -70,7 +70,7 @@ static guint gst_cltrimagesink_signals[LAST_SIGNAL] = { 0 }; enum { ARG_0, - ARG_WIDGET, + ARG_QUEUE, ARG_SYNCHRONOUS, ARG_SIGNAL_HANDOFFS /* FILL ME */ @@ -103,6 +103,15 @@ 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) @@ -110,8 +119,6 @@ gst_cltrimagesink_fixate (GstPad *pad, GstStructure *structure; GstCaps *newcaps; - DBG("mark"); - if (gst_caps_get_size (caps) > 1) return NULL; @@ -153,9 +160,11 @@ gst_cltrimagesink_getcaps (GstPad * pad) "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, 0xff, + /* + "red_mask", G_TYPE_INT, 0xff0000, + "green_mask", G_TYPE_INT, 0x0000ff, + "blue_mask", G_TYPE_INT, 0x00ff00, + */ "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); @@ -172,8 +181,6 @@ gst_cltrimagesink_sink_link (GstPad * pad, const GstCaps * caps) GstStructure *structure; Pixbuf *pixb = NULL; - DBG("mark"); - cltrimagesink = GST_CLTRIMAGESINK (gst_pad_get_parent (pad)); /* @@ -220,7 +227,7 @@ gst_cltrimagesink_sink_link (GstPad * pad, const GstCaps * caps) GST_VIDEOSINK_HEIGHT (cltrimagesink)); /* Is this the right place ? */ - cltrimagesink->texture = cltr_texture_new(pixb); + cltrimagesink->texture = cltr_texture_no_tile_new(pixb); pixbuf_unref(pixb); @@ -249,7 +256,6 @@ gst_cltrimagesink_change_state (GstElement * element) */ break; case GST_STATE_READY_TO_PAUSED: - printf ("ready to paused\n"); cltrimagesink->time = 0; break; case GST_STATE_PAUSED_TO_PLAYING: @@ -283,8 +289,6 @@ gst_cltrimagesink_chain (GstPad * pad, GstData * data) g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (buf != NULL); - DBG("mark"); - cltrimagesink = GST_CLTRIMAGESINK (gst_pad_get_parent (pad)); if (GST_IS_EVENT (data)) @@ -303,8 +307,6 @@ gst_cltrimagesink_chain (GstPad * pad, GstData * data) /* If this buffer has been allocated using our buffer management we * simply put the ximage which is in the PRIVATE pointer */ - DBG("time is is %li", cltrimagesink->time); - #if 0 if (GST_BUFFER_FREE_DATA_FUNC (buf) == gst_cltrimagesink_buffer_free) { @@ -323,38 +325,47 @@ gst_cltrimagesink_chain (GstPad * pad, GstData * data) /* 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) - memcpy (pixb->data, - GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), - pixb->bytes_per_line * pixb->width)); + { + /* + memcpy (pixb->data, + GST_BUFFER_DATA (buf), + MIN (GST_BUFFER_SIZE (buf), + pixb->bytes_per_line * pixb->width)); + */ - cltr_texture_resync_pixbuf(cltrimagesink->texture); + /* EVIL */ - /* - cltr_texture_render_to_gl_quad(cltrimagesink->texture, - 0, 0, 320, 240); - */ - + 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)); -#if 0 - memcpy (cltrimagesink->cltrimage->data, - GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), - cltrimagesink->cltrimage->size)); - - gst_cltrimagesink_ximage_put (cltrimagesink, - cltrimagesink->cltrimage); -#endif + } + + 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 ! */ - DBG("MARK, texture == NULL"); - gst_buffer_unref (buf); GST_ELEMENT_ERROR (cltrimagesink, CORE, NEGOTIATION, (NULL), ("no format defined before chain function")); @@ -406,8 +417,8 @@ gst_cltrimagesink_set_property (GObject *object, switch (prop_id) { - case ARG_WIDGET: - cltrimagesink->widget = g_value_get_pointer (value); + case ARG_QUEUE: + cltrimagesink->queue = g_value_get_pointer (value); break; /* case ARG_SIGNAL_HANDOFFS: @@ -434,8 +445,8 @@ gst_cltrimagesink_get_property (GObject *object, switch (prop_id) { - case ARG_WIDGET: - g_value_set_pointer (value, cltrimagesink->widget); + case ARG_QUEUE: + g_value_set_pointer (value, cltrimagesink->queue); break; /* case ARG_SIGNAL_HANDOFFS: @@ -472,8 +483,6 @@ gst_cltrimagesink_finalize (GObject *object) static void gst_cltrimagesink_init (GstCltrimageSink * cltrimagesink) { - DBG("mark"); - GST_VIDEOSINK_PAD (cltrimagesink) = gst_pad_new_from_template ( gst_static_pad_template_get(&gst_cltrimagesink_sink_template_factory), "sink"); @@ -536,10 +545,10 @@ gst_cltrimagesink_class_init (GstCltrimageSinkClass * klass) /* TOGO */ g_object_class_install_property (gobject_class, - ARG_WIDGET, - g_param_spec_pointer ("widget", - "Widget", - "Cltr drawable widget", + ARG_QUEUE, + g_param_spec_pointer ("queue", + "Queue", + "Async Signal Queue", G_PARAM_READWRITE)); /* TOGO */ diff --git a/gst/cltrimagesink.h b/gst/cltrimagesink.h index 1c724c1b8..a31f32d2e 100644 --- a/gst/cltrimagesink.h +++ b/gst/cltrimagesink.h @@ -37,9 +37,9 @@ struct _GstCltrimageSink GMutex *pool_lock; GSList *image_pool; - GstCaps *caps; + GstCaps *caps; + GAsyncQueue *queue; - CltrWidget *widget; }; struct _GstCltrimageSinkClass { @@ -52,6 +52,7 @@ struct _GstCltrimageSinkClass { GType gst_cltrimagesink_get_type(void); /* XXX needed ? */ + G_END_DECLS #endif /* __GST_CLTRIMAGESINK_H__ */