Author: miguel
Date: 2007-05-25 18:11:36 -0400 (Fri, 25 May 2007)
New Revision: 77979
Added:
trunk/moon/
trunk/moon/AUTHORS
trunk/moon/COPYING
trunk/moon/ChangeLog
trunk/moon/INSTALL
trunk/moon/LICENSE
trunk/moon/Makefile.am
trunk/moon/NEWS
trunk/moon/README
trunk/moon/autogen.sh
trunk/moon/configure.ac
trunk/moon/oMakefile
trunk/moon/src/
trunk/moon/src/ChangeLog
trunk/moon/src/Makefile.am
trunk/moon/src/demo.c
trunk/moon/src/runtime.c
trunk/moon/src/runtime.h
trunk/moon/src/video.c
trunk/moon/src/video.cpp
Log:
Moonlight C runtime
Added: trunk/moon/AUTHORS
===================================================================
--- trunk/moon/AUTHORS 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/AUTHORS 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1 @@
+Miguel de Icaza, [EMAIL PROTECTED]
Added: trunk/moon/COPYING
===================================================================
--- trunk/moon/COPYING 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/COPYING 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1 @@
+See the file LICENSE for details
Added: trunk/moon/ChangeLog
===================================================================
Added: trunk/moon/INSTALL
===================================================================
Added: trunk/moon/LICENSE
===================================================================
--- trunk/moon/LICENSE 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/LICENSE 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,8 @@
+This code is licensed under the terms of the GNU LGPL 2 license.
+
+In addition to the GNU LGPL, this code is available for relicensing
+for non-LGPL use, contact Novell for details ([EMAIL PROTECTED])
+
+This code might contain code that optionally links to LGPL and
+GPL code, in those cases, if the library is built with those
+bits the code is covered under those licenses.
Added: trunk/moon/Makefile.am
===================================================================
--- trunk/moon/Makefile.am 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/Makefile.am 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1 @@
+SUBDIRS = src
Added: trunk/moon/NEWS
===================================================================
Added: trunk/moon/README
===================================================================
--- trunk/moon/README 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/README 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,121 @@
+This contains a minimal runtime in C for trying out some ideas for the
+Moonlight binding. It is not designed to be our final implementation.
+
+The C++ file here was merely to test Agg, but the public API is pure C
+and without agg (which is currently disabled due to laziness on my
+part) it should build with a C compiler
+
+This is not likely the final version of this code.
+
+* Object System
+
+ This contains a poor man's object system.
+
+ The vtable is the first field in the base object (Item in
+ this case) and is encoded as a void *. You must cast this
+ to ItemVtable to be able to call methods. I do not remember
+ why I did not just go for the hardcoded ItemVtable there.
+
+ Should be fixed perhaps.
+
+ The various XXX_init() methods are here merely to initialize the
+ vtable: they should call into the parent, and then overwrite th
+ vtable if they need to.
+
+* Items
+
+ Items for the base class for all the objects that are rendered,
+ items contain a bounding box (double x1, y1, x2, y2) which must
+ be updated when the virtual method ->getbounds is called.
+
+ In addition each item can contain an affine transformation, the
+ affine transformation is relative. This means that the affine
+ is relative to the parent.
+
+ I chose relative vs absolute for the items as changing an affine
+ in the managed world for a parent would have to change all the
+ affines for all the children contained. With this approach,
+ we can change the affine for a parent, and all the children
+ will get the new affine transformation.
+
+ The encoding of the affine transformation is done with a
+ "double *" which, if not-NULL should point to six doubles in
+ the format expected by cairo_matrix_t (and libart).
+
+ The double [6] can be casted into a cairo_matrix_t, which is why
+ this appers like that in the source code. This was done in
+ case we want to switch to AGG.
+
+ A method to obtain the actual affine that applies to this object is:
+
+ double *item_get_affine (double *container, double *affine, double
*result);
+
+ The "container" should be the affine passed by the parent, the "affine"
is the
+ item affine (either one can be null) and the compound affine transform
is
+ left in "result".
+
+ The "result" has to be allocated by the parent, if both container and
affine
+ are null, the NULL value is returned from item_get_affine, so a common
+ code pattern used is:
+
+ double actual [6];
+ double *use_affine = item_get_affine (affine, item->xform, actual);
+
+ And then `use_affine' is used.
+
+* Rendering in Items
+
+ Rendering currently passes the parent affine, but it might be possible
to
+ avoid this if we end up using Cairo: just use the affine that is part
of
+ the cairo context at the time of the rendering.
+
+* Video
+
+ The video stuff is *incredibly* early at this point and
+ requires an FFmpeg installation from SVN (the only available
+ one).
+
+ The video also has a video hardcoded for now.
+
+ Currently this is very basic, it merely does video frame decoding, and
+ makes no attempt to keep track of the clock (as it should) nor to do any
+ kind of audio output (yet).
+
+ The video is also busted, I do not know why, but the "decoded"
+ video is incorrect, it has the wrong colors.
+
+ The caching is substandard and we create new surfaces when we do not
need
+ to create them. We could create the RGB buffer and the
+ surface just once and reuse these.
+
+ We are using cairo_paint, which renders without an affine
+ transformation applied, which means that item_apply_transform
+ is a no-op, this is broken and must be fixed.
+
+* Rendering
+
+ Currently we are creating a bitmap surface and we always copy
+ it to the screen.
+
+ We probably should move to cairo surfaces directly.
+
+* Expose
+
+ Currently repaints happen with an item_invalidate, I need to
+ research if this clears the background before repainting.
+
+* Usage of C++
+
+ I do not know how to initialize instance fields in a structure
+ with the contructor, so there is code like this:
+
+ struct {
+ Agg2D *graphics;
+ }
+
+ Then:
+
+ something->graphics = new Agg2D ()
+
+ Followed by uses of graphics in that way, there is probably a
+ better way.
Added: trunk/moon/autogen.sh
===================================================================
--- trunk/moon/autogen.sh 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/autogen.sh 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,142 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+# Ripped off from GNOME macros version
+
+DIE=0
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+if [ -n "$MONO_PATH" ]; then
+ # from -> /mono/lib:/another/mono/lib
+ # to -> /mono /another/mono
+ for i in `echo ${MONO_PATH} | tr ":" " "`; do
+ i=`dirname ${i}`
+ if [ -n "{i}" -a -d "${i}/share/aclocal" ]; then
+ ACLOCAL_FLAGS="-I ${i}/share/aclocal $ACLOCAL_FLAGS"
+ fi
+ if [ -n "{i}" -a -d "${i}/bin" ]; then
+ PATH="${i}/bin:$PATH"
+ fi
+ done
+ export PATH
+fi
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`autoconf' installed to compile Mono."
+ echo "Download the appropriate package for your distribution,"
+ echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+}
+
+if [ -z "$LIBTOOL" ]; then
+ LIBTOOL=`which glibtool 2>/dev/null`
+ if [ ! -x "$LIBTOOL" ]; then
+ LIBTOOL=`which libtool`
+ fi
+fi
+
+(grep "^AM_PROG_LIBTOOL" $srcdir/configure.ac >/dev/null) && {
+ ($LIBTOOL --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`libtool' installed to compile Mono."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+ }
+}
+
+grep "^AM_GNU_GETTEXT" $srcdir/configure.ac >/dev/null && {
+ grep "sed.*POTFILES" $srcdir/configure.ac >/dev/null || \
+ (gettext --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`gettext' installed to compile Mono."
+ echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+ }
+}
+
+(automake --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: You must have \`automake' installed to compile Mono."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+ NO_AUTOMAKE=yes
+}
+
+
+# if no automake, don't bother testing for aclocal
+test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "**Error**: Missing \`aclocal'. The version of \`automake'"
+ echo "installed doesn't appear recent enough."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+}
+
+if test "$DIE" -eq 1; then
+ exit 1
+fi
+
+if test -z "$*"; then
+ echo "**Warning**: I am going to run \`configure' with no arguments."
+ echo "If you wish to pass any to it, please specify them on the"
+ echo \`$0\'" command line."
+ echo
+fi
+
+case $CC in
+xlc )
+ am_opt=--include-deps;;
+esac
+
+
+if grep "^AM_PROG_LIBTOOL" configure.ac >/dev/null; then
+ if test -z "$NO_LIBTOOLIZE" ; then
+ echo "Running libtoolize..."
+ ${LIBTOOL}ize --force --copy
+ fi
+fi
+
+echo "Running aclocal $ACLOCAL_FLAGS ..."
+aclocal $ACLOCAL_FLAGS || {
+ echo
+ echo "**Error**: aclocal failed. This may mean that you have not"
+ echo "installed all of the packages you need, or you may need to"
+ echo "set ACLOCAL_FLAGS to include \"-I \$prefix/share/aclocal\""
+ echo "for the prefix where you installed the packages whose"
+ echo "macros were not found"
+ exit 1
+}
+
+if grep "^AM_CONFIG_HEADER" configure.ac >/dev/null; then
+ echo "Running autoheader..."
+ autoheader || { echo "**Error**: autoheader failed."; exit 1; }
+fi
+
+echo "Running automake --gnu $am_opt ..."
+automake --add-missing --gnu $am_opt ||
+ { echo "**Error**: automake failed."; exit 1; }
+echo "Running autoconf ..."
+autoconf || { echo "**Error**: autoconf failed."; exit 1; }
+
+if test -d $srcdir/libgc; then
+ echo Running libgc/autogen.sh ...
+ (cd $srcdir/libgc ; NOCONFIGURE=1 ./autogen.sh "$@")
+ echo Done running libgc/autogen.sh ...
+fi
+
+
+conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso-c
+
+if test x$NOCONFIGURE = x; then
+ echo Running $srcdir/configure $conf_flags "$@" ...
+ $srcdir/configure $conf_flags "$@" \
+ && echo Now type \`make\' to compile $PKG_NAME || exit 1
+else
+ echo Skipping configure process.
+fi
Property changes on: trunk/moon/autogen.sh
___________________________________________________________________
Name: svn:executable
+
Name: svn:eol-style
+ native
Added: trunk/moon/configure.ac
===================================================================
--- trunk/moon/configure.ac 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/configure.ac 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,43 @@
+AC_INIT(README)
+AC_CANONICAL_SYSTEM
+
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(moon,0.1)
+AM_MAINTAINER_MODE
+AC_PROG_CXX
+AC_HEADER_STDC
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+LIBS_TO_CHECK="gtk+-2.0 libavcodec libavformat gthread-2.0 libswscale"
+
+if pkg-config gtk+-2.0; then
+ echo Gtk+ 2.0 found
+else
+ echo Gtk+ 2.0 development kit is missing
+ exit 1
+fi
+
+#
+# these come from ffmpeg
+#
+if pkg-config libavcodec libavformat libswscale ; then
+ echo ffmpeg developer installation found
+else
+ echo ffmpeg and its associated libraries are not installed
+ echo You need libavcodec, libavformat and libswscale development kits
+ exit 1
+fi
+
+CFLAGS="$CFLAGS `pkg-config --cflags gtk+-2.0 libavcodec libavformat
gthread-2.0 libswscale`"
+CXXFLAGS="$CXXFLAGS `pkg-config --cflags gtk+-2.0 libavcodec libavformat
gthread-2.0 libswscale`"
+LIBS="$LIBS `pkg-config --libs gtk+-2.0 libavcodec libavformat gthread-2.0
libswscale`"
+
+AC_SUBST(CFLAGS)
+AC_SUBST(CXXFLAGS)
+AC_SUBST(LIBS)
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+])
\ No newline at end of file
Added: trunk/moon/oMakefile
===================================================================
--- trunk/moon/oMakefile 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/oMakefile 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,22 @@
+SOURCES = runtime.cpp
+OBJS = runtime.o video.o
+
+HEADERS=`pkg-config --libs gtk+-2.0 libagg libavcodec libavformat gthread-2.0
libswscale`
+LIBS=`pkg-config --cflags gtk+-2.0 libavcodec libavformat gthread-2.0
libswscale freetype2`
+
+CXX=c++ -Wall
+
+demo: runtime.o video.o
+ $(CXX) -g -o demo $(OBJS) $(HEADERS)
+
+demoagg: runtime.o video.o Agg2D.o
+ $(CXX) -g -o demo $(OBJS) $(HEADERS) -laggfontfreetype `pkg-config
--libs libagg`
+
+runtime.o: runtime.cpp runtime.h Agg2D.h
+ $(CXX) -g -c runtime.cpp $(LIBS)
+
+video.o: video.c runtime.h Agg2D.h
+ $(CC) -g -c video.c $(LIBS)
+
+Agg2D.o: Agg2D.h Agg2D.cpp
+ $(CXX) -g -c Agg2D.cpp `pkg-config --cflags libagg freetype2`
\ No newline at end of file
Added: trunk/moon/src/ChangeLog
===================================================================
Added: trunk/moon/src/Makefile.am
===================================================================
--- trunk/moon/src/Makefile.am 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/src/Makefile.am 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,14 @@
+bin_PROGRAMS = demo
+
+lib_LTLIBRARIES = libmoon.la
+
+libmoon_la_SOURCES = \
+ runtime.c \
+ runtime.h \
+ video.c \
+ video.h
+
+demo_SOURCES = \
+ demo.c
+
+demo_LDADD = -lmoon
\ No newline at end of file
Added: trunk/moon/src/demo.c
===================================================================
--- trunk/moon/src/demo.c 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/src/demo.c 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,101 @@
+#define VIDEO_DEMO
+#include <string.h>
+#include <gtk/gtk.h>
+#include <malloc.h>
+#include <glib.h>
+#include <stdlib.h>
+
+#include "runtime.h"
+
+static Item *r, *v;
+
+gboolean
+expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+ Surface *t = (Surface *) data;
+
+ if (event->area.x > t->width || event->area.y > t->height)
+ return TRUE;
+
+ printf ("Got a request to repaint at %d %d %d %d\n", event->area.x,
event->area.y, event->area.width, event->area.height);
+ surface_repaint (t, event->area.x, event->area.y, event->area.width,
event->area.height);
+ gdk_draw_pixbuf (widget->window,
+ NULL,
+ t->pixbuf,
+ event->area.x, event->area.y, // gint src_x, gint
src_y,
+ event->area.x, event->area.y, // gint dest_x, gint
dest_y,
+ MIN (event->area.width, t->width),
+ MIN (event->area.height, t->height),
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0 // gint x_dither, gint y_dither
+ );
+ return TRUE;
+}
+
+static gboolean
+repaint (gpointer data)
+{
+ static double degree = 0;
+ static double degree2 = 0;
+ double trans [6];
+ double trans2 [6];
+
+ cairo_matrix_init_rotate ((cairo_matrix_t *)&trans, degree);
+ degree += 0.01;
+
+ if (v != NULL)
+ item_transform_set (v, (double *) trans);
+
+ cairo_matrix_init_rotate ((cairo_matrix_t *)&trans2, degree2);
+ degree2 -= 0.1;
+ item_transform_set (r, (double *) trans2);
+
+ return TRUE;
+}
+
+int
+main (int argc, char *argv [])
+{
+ GtkWidget *w;
+ GtkWidget *da;
+ cairo_matrix_t trans;
+
+ gtk_init (&argc, &argv);
+ g_thread_init (NULL);
+ gdk_threads_init ();
+
+ w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ da = gtk_drawing_area_new ();
+ gtk_container_add (GTK_CONTAINER (w), da);
+
+ // Create our objects
+ Surface *t = surface_new (600, 600);
+ t->data = w;
+ r = rectangle_new (100, 100, 100, 100);
+ cairo_matrix_init_rotate (&trans, 0.4);
+ item_transform_set (r, (double *) (&trans));
+ surface_repaint (t, 0, 0, 300, 300);
+
+#ifdef VIDEO_DEMO
+ v = video_new ("file:///tmp/BoxerSmacksdownInhoffe.wmv", 0, 0);
+ //printf ("Got %d\n", v);
+ item_transform_set (v, (double *) (&trans));
+ group_item_add ((Group *) t, v);
+#endif
+
+ group_item_add ((Group *) t, r);
+
+#ifdef VIDEO_DEMO
+ Item *v2 = video_new ("file:///tmp/Countdown-Colbert-BestNailings.wmv",
100, 100);
+ group_item_add ((Group *) t, v2);
+#endif
+
+ gtk_signal_connect (GTK_OBJECT (w), "expose_event",
+ G_CALLBACK (expose_event_callback), t);
+
+ gtk_widget_set_usize (w, 400, 400);
+ gtk_widget_show (w);
+ gtk_timeout_add (60, repaint, w);
+ //g_idle_add (repaint, w);
+ gtk_main ();
+}
Property changes on: trunk/moon/src/demo.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/moon/src/runtime.c
===================================================================
--- trunk/moon/src/runtime.c 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/src/runtime.c 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,442 @@
+/*
+ * runtime.cpp: Core surface and canvas definitions.
+ *
+ * Author:
+ * Miguel de Icaza ([EMAIL PROTECTED])
+ *
+ * Copyright 2007 Novell, Inc. (http://www.novell.com)
+ *
+ * See the LICENSE file included with the distribution for details.
+ *
+ */
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <malloc.h>
+#include <glib.h>
+#include <stdlib.h>
+#if AGG
+# include <agg_rendering_buffer.h>
+# include "Agg2D.h"
+#else
+# define CAIRO 1
+#endif
+
+#include "runtime.h"
+
+#if AGG
+struct _SurfacePrivate {
+ agg::rendering_buffer rbuf;
+ Agg2D *graphics;
+};
+#endif
+
+Surface *item_surface_get (Item *item);
+
+static void
+vt_item_render (Item *item, Surface *s, double *affine, int x, int y, int
width, int height)
+{
+ fprintf (stderr, "vt_item_render called, you must implement this
method");
+}
+
+static void
+vt_item_getbounds (Item *item)
+{
+ fprintf (stderr, "vt_item_getbounds called, you must implement this
method");
+}
+
+static ItemVtable item_vtable = { &vt_item_render, &vt_item_getbounds };
+
+/**
+ * item_getbounds:
+ * @item: the item to update the bounds of
+ *
+ * Does this by requesting bounds update to all of its parents.
+ */
+void
+item_update_bounds (Item *item)
+{
+ double cx1 = item->x1;
+ double cy1 = item->y1;
+ double cx2 = item->x2;
+ double cy2 = item->y2;
+
+ ItemVtable *vt = (ItemVtable *) item->vtable;
+ vt->getbounds (item);
+
+ //
+ // If we changed, notify the parent to recompute its bounds
+ //
+ if (item->x1 != cx1 || item->y1 != cy1 || item->y2 != cy2 || item->x2
!= cx2){
+ if (item->parent != NULL)
+ item_update_bounds (item->parent);
+ }
+}
+
+void
+item_init (Item *item)
+{
+ item->vtable = &item_vtable;
+}
+
+/*
+ * item_get_affine:
+ * @container: the affine transform from the container
+ * @affine: the affine transform for this item
+ * @result: a place that can contain 6 doubles where the data is saved
+ *
+ * Composites the container affine transformation with the item affine
+ * transformation.
+ *
+ * Returns the pointer to result if the caller must apply affine
+ * transformations, or NULL if the affine should not be used.
+ */
+double *
+item_get_affine (double *container, double *affine, double *result)
+{
+ int i;
+
+ if (container == NULL){
+ if (affine == NULL)
+ return FALSE;
+ for (i = 0; i < 6; i++)
+ result [i] = affine [i];
+ return result;
+ }
+ if (affine == NULL){
+ for (i = 0; i < 6; i++)
+ result [i] = container [i];
+ return result;
+ }
+
+ result [0] = container [0] * affine [0] + container [1] * affine [2];
+ result [1] = container [0] * affine [1] + container [1] * affine [3];
+ result [2] = container [2] * affine [0] + container [3] * affine [2];
+ result [3] = container [2] * affine [1] + container [3] * affine [3];
+ result [4] = container [4] * affine [0] + container [5] * affine [2] +
affine [4];
+ result [5] = container [4] * affine [1] + container [5] * affine [3] +
affine [5];
+
+ return result;
+}
+
+void
+item_destroy (Item *item)
+{
+ if (item->xform)
+ free (item->xform);
+}
+
+//
+// item_affine_get_absolute:
+//
+// Returns the absolute affine transformation for this given item
+// (composing the full chain from the top to this item)
+//
+double *
+item_affine_get_absolute (Item *item, double *result)
+{
+ double res [6];
+ double *ret;
+
+ if (item->parent == NULL){
+ return item_get_affine (NULL, item->xform, result);
+ }
+
+ ret = item_affine_get_absolute (item->parent, res);
+ return item_get_affine (ret, item->xform, result);
+}
+
+void
+item_invalidate (Item *item)
+{
+ double res [6];
+ double *affine = item_affine_get_absolute (item, res);
+ Surface *s = item_surface_get (item);
+
+ if (s == NULL)
+ return;
+
+#ifdef DEBUG_INVALIDATE
+ printf ("Requesting invalidate for %d %d %d %d\n",
+ (int) item->x1, (int)item->y1,
+ (int)(item->x2-item->x1),
(int)(item->y2-item->y1));
+#endif
+ gtk_widget_queue_draw_area ((GtkWidget *)s->data,
+ (int) item->x1, (int)item->y1,
+ (int)(item->x2-item->x1),
(int)(item->y2-item->y1));
+}
+
+void
+item_transform_set (Item *item, double *transform)
+{
+ double *d;
+
+ item_invalidate (item);
+
+ if (item->xform)
+ free (item->xform);
+
+ if (transform == NULL)
+ item->xform = transform;
+ else {
+ d = (double *) malloc (sizeof (double) * 6);
+
+ d [0] = transform [0];
+ d [1] = transform [1];
+ d [2] = transform [2];
+ d [3] = transform [3];
+ d [4] = transform [4];
+ d [5] = transform [5];
+
+ item->xform = d;
+ }
+ ItemVtable *vt = (ItemVtable *) item->vtable;
+ vt->getbounds (item);
+ item_invalidate (item);
+}
+
+static void
+group_render (Item *item, Surface *s, double *affine, int x, int y, int width,
int height)
+{
+ Group *group = (Group *) item;
+ GSList *il;
+ double actual [6];
+ double *use_affine = item_get_affine (affine, item->xform, actual);
+
+ for (il = group->items; il != NULL; il = il->next){
+ Item *item = (Item *) il->data;
+ ItemVtable *vt = (ItemVtable *) item->vtable;
+
+ vt->render (item, s, use_affine, x, y, width, height);
+ }
+}
+
+static void
+group_getbounds (Item *item)
+{
+
+}
+
+static ItemVtable group_vtable = { &group_render, &group_getbounds };
+
+void
+group_init (Group *group)
+{
+ item_init (&group->item);
+ group->item.vtable = &group_vtable;
+}
+
+void
+group_item_add (Group *group, Item *item)
+{
+ group->items = g_slist_append (group->items, item);
+ item->parent = (Item *) group;
+
+ ItemVtable *vt = (ItemVtable *) item->vtable;
+ vt->getbounds (item);
+}
+
+void
+shape_init (Shape *shape)
+{
+ item_init (&shape->item);
+}
+
+static void
+rectangle_draw (Item *item, Surface *s, double *affine)
+{
+ Rectangle *r = (Rectangle *) item;
+ double result [6];
+ double *matrix = item_get_affine (affine, item->xform, result);
+
+ cairo_save (s->cairo);
+ if (matrix != NULL)
+ cairo_set_matrix (s->cairo, (cairo_matrix_t *) matrix);
+
+ cairo_rectangle (s->cairo, r->x, r->y, r->w, r->h);
+ cairo_restore (s->cairo);
+}
+
+static ItemVtable surface_vtable = { &group_render, &group_getbounds };
+
+Surface *
+item_surface_get (Item *item)
+{
+ if (item->vtable == &surface_vtable)
+ return (Surface *) item;
+ if (item->parent != NULL)
+ return item_surface_get (item->parent);
+
+ return NULL;
+}
+
+static void
+rectangle_render (Item *item, Surface *s, double *affine, int x, int y, int
width, int height)
+{
+#if CAIRO
+ rectangle_draw (item, s, affine);
+ cairo_stroke (s->cairo);
+#else
+ Rectangle *r = (Rectangle *) item;
+ Agg2D *g = s->priv->graphics;
+
+ double result[6];
+ double *matrix = item_get_affine (affine, item->xform, result);
+
+ if (matrix != NULL){
+ Agg2D::Affine a (matrix [0], matrix [1], matrix [2], matrix
[3], matrix [4], matrix [5]);
+
+ g->affine (a);
+ }
+ g->lineColor (0, 0, 0);
+ g->noFill ();
+ g->rectangle (r->x, r->y, r->x + r->w, r->y + r->h);
+ if (matrix != NULL)
+ g->resetTransformations ();
+#endif
+}
+
+static void
+rectangle_getbounds (Item *item)
+{
+ double res [6];
+ double *affine = item_affine_get_absolute (item, res);
+
+ Surface *s = item_surface_get (item);
+ if (s == NULL){
+ // not yet attached
+ return;
+ }
+#if CAIRO
+ rectangle_draw (item, s, affine);
+ cairo_stroke_extents (s->cairo, &item->x1, &item->y1, &item->x2,
&item->y2);
+ cairo_new_path (s->cairo);
+#else
+#endif
+}
+
+static ItemVtable rectangle_vtable = { &rectangle_render, rectangle_getbounds
};
+
+void
+rectangle_init (Rectangle *rectangle)
+{
+ shape_init (&rectangle->shape);
+ Item *i = &rectangle->shape.item;
+ i->vtable = &rectangle_vtable;
+}
+
+Item *
+rectangle_new (double x, double y, double w, double h)
+{
+ Rectangle *rect = g_new0 (Rectangle, 1);
+ rectangle_init (rect);
+
+ rect->x = x;
+ rect->y = y;
+ rect->w = w;
+ rect->h = h;
+
+ return (Item*)rect;
+}
+
+void
+surface_clear (Surface *s, int x, int y, int width, int height)
+{
+ if (x < 0){
+ width -= x;
+ x = 0;
+ }
+
+ if (y < 0){
+ height -= y;
+ y = 0;
+ }
+ width = MAX (0, MIN (width, s->width));
+ height = MAX (0, MIN (height, s->height));
+
+ int stride = s->width * 4;
+ unsigned char *dest = s->buffer + (y * stride) + (x * 4);
+
+ while (height--){
+ memset (dest, 14, width * 4);
+ dest += stride;
+ }
+}
+
+void
+surface_clear_all (Surface *s)
+{
+ memset (s->buffer, 14, s->width * s->height * 4);
+}
+
+static void
+surface_realloc (Surface *s)
+{
+ if (s->buffer){
+ free (s->buffer);
+ gdk_pixbuf_unref (s->pixbuf);
+ }
+
+ int size = s->width * s->height * 4;
+ s->buffer = (unsigned char *) malloc (size);
+ surface_clear_all (s);
+
+ //
+ // Hook up our surfaces
+ //
+
+ s->pixbuf = gdk_pixbuf_new_from_data (s->buffer, GDK_COLORSPACE_RGB,
TRUE, 8,
+ s->width, s->height, s->width *
4, NULL, NULL);
+
+#if AGG
+ s->priv = g_new0 (SurfacePrivate, 1);
+ s->priv->rbuf = agg::rendering_buffer ();
+ s->priv->rbuf.attach (s->buffer, s->width, s->height, s->width * 4);
+ s->priv->graphics = new Agg2D();
+ s->priv->graphics->attach (s->buffer, s->width, s->height, s->width *
4);
+ s->priv->graphics->viewport (0, 0, s->width, s->height, 0, 0, s->width,
s->height, Agg2D::XMidYMid);
+#else
+
+ s->cairo_surface = cairo_image_surface_create_for_data (s->buffer,
CAIRO_FORMAT_ARGB32, s->width, s->height, s->width * 4);
+ s->cairo = cairo_create (s->cairo_surface);
+ //cairo_set_operator (s->cairo, CAIRO_OPERATOR_SOURCE);
+ //cairo_paint (s->cairo);
+ //cairo_set_operator (s->cairo, CAIRO_OPERATOR_SOURCE);
+ //cairo_set_source_rgb (s->cairo, 0, 1, 0);
+#endif
+}
+
+void
+surface_init (Surface *s, int width, int height)
+{
+ group_init (&s->group);
+ s->group.item.vtable = &surface_vtable;
+ s->width = width;
+ s->height = height;
+ surface_realloc (s);
+}
+
+void
+surface_destroy (Surface *s)
+{
+ cairo_surface_destroy (s->cairo_surface);
+ free (s);
+}
+
+Surface *
+surface_new (int width, int height)
+{
+ Surface *s = g_new0 (Surface, 1);
+
+ surface_init (s, width, height);
+
+ return s;
+}
+
+void
+surface_repaint (Surface *s, int x, int y, int width, int height)
+{
+ surface_clear (s, x, y, width, height);
+ group_render ((Item *) s, s, NULL, x, y, width, height);
+}
+
Property changes on: trunk/moon/src/runtime.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/moon/src/runtime.h
===================================================================
--- trunk/moon/src/runtime.h 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/src/runtime.h 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,134 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cairo.h>
+
+typedef struct _Item Item;
+typedef struct _Surface Surface;
+
+typedef struct {
+ //
+ // render:
+ // Renders the given @item on the @surface. The parent affine
transformation is in
+ // @affine, and the area that is exposed is delimited by x, y, width,
height
+ //
+ void (*render) (Item *item, Surface *surface, double *affine, int x,
int y, int width, int height);
+
+ //
+ // getbounds:
+ // Updates the bounding box for the given item, this uses the parent
+ // chain to compute the composite affine.
+ //
+ // Input parameters:
+ // @item: the item
+ //
+ // Output:
+ // the item->x1,y1,x2,y2 values are updated.
+ //
+ void (*getbounds) (Item *item);
+} ItemVtable;
+
+struct _Item {
+ void *vtable;
+
+ // OpacityProperty;
+ // ClipProperty;
+ // RenderTransformProperty;
+ // TriggersProperty;
+ // OpacityMaskProperty;
+ // RenderTransformOriginProperty;
+ // CursorProperty;
+ // IsHitTestVisibleProperty;
+ // VisibilityProperty;
+ // ResourcesProperty;
+ // ZIndexProperty;
+
+ Item *parent;
+
+ // The computed bounding box
+ double x1, y1, x2, y2;
+
+ // If null, identity, otherwise affine transformation.
+ double *xform;
+};
+
+Surface *item_surface_get (Item *item);
+void item_init (Item *item);
+void item_destroy (Item *item);
+void item_invalidate (Item *item);
+void item_update_bounds (Item *item);
+void item_transform_set (Item *item, double *transform);
+double *item_get_affine (double *container, double *affine, double
*result);
+Surface *item_surface_get (Item *item);
+double *item_affine_get_absolute (Item *item, double *result);
+
+typedef struct {
+ Item item;
+
+ GSList *items;
+} Group;
+
+void group_init (Group *group);
+void group_item_add (Group *group, Item *item);
+
+typedef struct {
+ Item item;
+
+ // Brush: Fill, Stroke
+} Shape;
+
+void shape_init (Shape *shape);
+
+typedef struct {
+ Shape shape;
+ double x, y, w, h;
+} Rectangle;
+
+void rectangle_init (Rectangle *rectangle);
+Item *rectangle_new (double x, double y, double w, double h);
+
+// A video is an Item
+typedef struct _Video Video;
+
+void video_init (Video *video);
+Item *video_new (const char *filename, double x, double y);
+void video_destroy (Video *video);
+
+typedef struct _SurfacePrivate SurfacePrivate;
+
+struct _Surface {
+ Group group;
+
+ int width, height;
+
+ // The data lives here
+ unsigned char *buffer;
+
+ // Representations:
+
+ SurfacePrivate *priv;
+
+ // The same buffer, but this one is the pixbuf representation.
+ GdkPixbuf *pixbuf;
+
+ // The same buffer, but this one is for cairo.
+ cairo_surface_t *cairo_surface;
+ cairo_t *cairo;
+
+ //
+ // Consumer-defined data, we use it to pass the handle to invalidate
+ //
+ void *data;
+};
+
+Surface *surface_new (int width, int height);
+void surface_init (Surface *s, int width, int height);
+void surface_clear (Surface *s, int x, int y, int width, int height);
+void surface_clear_all (Surface *s);
+void surface_destroy (Surface *s);
+void surface_repaint (Surface *s, int x, int y, int width, int height);
+
+#ifdef __cplusplus
+};
+#endif
Property changes on: trunk/moon/src/runtime.h
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/moon/src/video.c
===================================================================
--- trunk/moon/src/video.c 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/src/video.c 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,398 @@
+/*
+ * video.c: The moonlight's video item
+ *
+ * Author:
+ * Miguel de Icaza ([EMAIL PROTECTED])
+ *
+ * Copyright 2007 Novell, Inc. (http://www.novell.com)
+ *
+ * See the LICENSE file included with the distribution for details.
+ *
+ */
+#include <string.h>
+#include <gtk/gtk.h>
+#include <cairo.h>
+#include <malloc.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include "runtime.h"
+
+//
+#include <fcntl.h>
+
+// video specific
+#include <stdint.h>
+#include <avcodec.h>
+#include <avformat.h>
+#include <swscale.h>
+
+typedef enum {
+ VIDEO_OK,
+ VIDEO_ERROR_OPEN,
+ VIDEO_ERROR_STREAM_INFO
+} VideoError;
+
+typedef enum {
+ // When a new frame is ready
+ CMD_NEWFRAME,
+
+ // When the video has been loaded, this updates the bounding box in the
Gtk+ GUI thread.
+ CMD_INITED
+} GuiCommand;
+
+struct _Video {
+ Item item;
+ double x, y, w, h;
+ char *filename;
+
+ int error;
+
+ GThread *decode_thread_id;
+ int pipe [2];
+
+ //
+ // AV Fields
+ //
+ AVFormatContext *av_format_context;
+
+ // Video
+ AVCodec *video_codec;
+ AVStream *video_stream;
+ int video_stream_idx;
+ GMutex *video_mutex;
+
+ GAsyncQueue *video_frames;
+
+ //
+ // The components used to render the buffer
+ //
+
+ // The buffer where we store the RGB data
+ void *video_rgb_buffer;
+
+ // The cairo surface that represents video_rgb_buffer
+ cairo_surface_t *video_cairo_surface;
+
+ // The SwsContext image convertor
+ struct SwsContext *video_scale_context;
+
+};
+
+static GMutex *video_lock;
+
+static void
+video_getbounds (Item *item)
+{
+ Video *video = (Video *) item;
+ double res [6];
+ double *affine = item_affine_get_absolute (item, res);
+ AVCodecContext *cc;
+
+ Surface *s = item_surface_get (item);
+ if (s == NULL){
+ // not yet attached
+ return;
+ }
+
+ // If we have not been initialized yet, we cant compute the bounds
+ if (video->video_stream == NULL || video->video_stream->codec == NULL){
+ item->x1 = item->y1 = item->x2 = item->y2 = 0;
+ return;
+ }
+ cc = video->video_stream->codec;
+
+ cairo_save (s->cairo);
+ if (affine != NULL)
+ cairo_set_matrix (s->cairo, (cairo_matrix_t *) affine);
+
+ cairo_rectangle (s->cairo, video->x, video->y, video->x + cc->width,
video->y + cc->height);
+ cairo_fill_extents (s->cairo, &item->x1, &item->y1, &item->x2,
&item->y2);
+
+ printf ("New video bounds: %g %g %g %g\n", item->x1, item->y1,
item->x2, item->y2);
+ cairo_restore (s->cairo);
+}
+
+static void video_render (Item *item, Surface *s, double *affine, int x, int
y, int width, int height);
+static int video_inited;
+static ItemVtable video_vtable = { &video_render, &video_getbounds };
+
+void
+video_init (Video *video)
+{
+ Item *item = &video->item;
+ item_init (item);
+ item->vtable = &video_vtable;
+
+ if (!video_inited){
+ video_lock = g_mutex_new ();
+ avcodec_init ();
+ av_register_all ();
+ avcodec_register_all ();
+ video_inited = TRUE;
+ }
+}
+
+static void
+send_command (Video *video, uint8_t cmd)
+{
+ int ret;
+
+ do {
+ ret = write (video->pipe [1], &cmd, 1);
+ } while (ret == -1 && errno == EINTR);
+}
+
+//
+// The decoder thread, runs until complete
+//
+static gpointer
+decoder (gpointer data)
+{
+ Video *video = data;
+ AVFrame *video_frame;
+ int i;
+ int video_stream_idx;
+
+ printf ("Video THREAD STARTS\n");
+
+ g_mutex_lock (video_lock);
+ // avcodec setup
+ // auto-detect format
+ // default buffer size
+ // no additional parameters
+ if (av_open_input_file (&video->av_format_context, video->filename,
NULL, 0, NULL) < 0){
+ g_error ("ERROR: open input file\n");
+ }
+ if (video->av_format_context == (void *) &rtsp_demuxer){
+ g_error ("ERROR: stream info\n");
+ }
+
+ av_read_play (video->av_format_context);
+
+ if (av_find_stream_info(video->av_format_context) < 0){
+ g_error ("ERROR: stream info\n");
+ }
+
+ for (i = 0; i < video->av_format_context->nb_streams; i++){
+ AVStream *stream = video->av_format_context->streams [i];
+ AVCodecContext *cc;
+
+ switch (stream->codec->codec_type){
+ case CODEC_TYPE_VIDEO:
+ video->video_codec = avcodec_find_decoder
(stream->codec->codec_id);
+ video->video_stream = video->av_format_context->streams
[i];
+ avcodec_open (video->video_stream->codec,
video->video_codec);
+ video->video_stream_idx = i;
+ video_stream_idx = i;
+
+ //
+ // Allocate our rendering buffer and cairo surface
+ //
+ cc = video->video_stream->codec;
+ video->video_rgb_buffer = malloc (cc->width *
cc->height * 4);
+
+ video->video_cairo_surface =
cairo_image_surface_create_for_data (
+ video->video_rgb_buffer, CAIRO_FORMAT_ARGB32,
+ cc->width, cc->height, cc->width * 4);
+
+ // The YUB to RGB scaleter/translator
+ video->video_scale_context = sws_getContext (cc->width,
cc->height, cc->pix_fmt, cc->width, cc->height,
+
PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
+ break;
+ }
+ }
+ g_mutex_unlock (video_lock);
+
+ send_command (video, CMD_INITED);
+
+ while (TRUE){
+ AVPacket packet, *pkt = &packet;
+
+ int ret;
+
+ ret = av_read_frame (video->av_format_context, pkt);
+ if (ret == -1){
+ printf ("Failed to read frame, terminating\n");
+ break;
+ }
+
+ if (pkt->stream_index == video_stream_idx){
+ int got_picture, n;
+
+ video_frame = avcodec_alloc_frame ();
+
+ while (g_async_queue_length (video->video_frames) > 10)
+ g_usleep (1000);
+
+ printf ("pkt=%ld\r", pkt->pts);
+ avcodec_decode_video (video->video_stream->codec,
video_frame, &got_picture, pkt->data, pkt->size);
+
+ if (got_picture){
+ g_mutex_lock (video->video_mutex);
+ send_command (video, CMD_NEWFRAME);
+ g_async_queue_push (video->video_frames,
video_frame);
+ g_mutex_unlock (video->video_mutex);
+ }
+ }
+ av_free_packet (pkt);
+ }
+
+ printf ("THREAD COMPLETES\n");
+
+ return NULL;
+}
+
+//
+// Convert the AVframe into an RGB buffer we can render
+//
+void
+convert_to_rgb (Video *video, AVFrame *frame)
+{
+ static struct SwsContext *img_convert_ctx;
+ AVCodecContext *cc = video->video_stream->codec;
+ AVPicture pict;
+ uint8_t *rgb_dest[3] = { video->video_rgb_buffer, NULL, NULL};
+ int rgb_stride [3] = { cc->width * 4, 0, 0 };
+
+ sws_scale (video->video_scale_context, frame->data, frame->linesize, 0,
+ video->video_stream->codec->height, rgb_dest, rgb_stride);
+}
+
+//
+// Called on the GUI thread when we got a frame to render.
+//
+gboolean
+video_ready (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ Video *video = (Video *) data;
+ AVFrame *frame;
+ int8_t commands [32];
+ int ret, i;
+
+ do {
+ ret = read (video->pipe [0], &commands, sizeof (commands));
+ } while ((ret == -1 && ret == EINTR));
+
+ // Nothing.
+ if (ret <= 0)
+ return TRUE;
+
+ for (i = 0; i < ret; i++){
+ switch (commands [i]){
+ case CMD_NEWFRAME:
+ item_invalidate ((Item *) video);
+ break;
+
+ case CMD_INITED:
+ item_update_bounds ((Item *) video);
+ break;
+
+ default:
+ fprintf (stderr, "video_ready: unknown command from
decoding thread (%d)\n", commands [i]);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+update_frame (Video *video)
+{
+ AVFrame *frame = NULL;
+
+ //
+ // Experimental strategy: the strategy needs to be entirely redone
+ // for now I just pull the last frame and discard all the other
+ // intermediate frames that we already decoded.
+ //
+ //
+ g_mutex_lock (video->video_mutex);
+ while (g_async_queue_length (video->video_frames) != 0){
+ void *rgb;
+
+ if (frame != NULL)
+ av_free (frame);
+
+ frame = (AVFrame *) g_async_queue_pop (video->video_frames);
+ }
+ g_mutex_unlock (video->video_mutex);
+
+ if (frame != NULL){
+ convert_to_rgb (video, frame);
+ av_free (frame);
+ }
+}
+
+static void
+video_render (Item *item, Surface *s, double *affine, int x, int y, int width,
int height)
+{
+ Video *video = (Video *) item;
+ double actual [6];
+ double *use_affine = item_get_affine (affine, item->xform, actual);
+ cairo_pattern_t *pattern, *old_pattern;
+
+ update_frame (video);
+
+ cairo_save (s->cairo);
+ if (use_affine != NULL)
+ cairo_set_matrix (s->cairo, (cairo_matrix_t *) use_affine);
+
+ cairo_translate (s->cairo, video->x, video->y);
+ cairo_set_source_surface (s->cairo, video->video_cairo_surface, 0, 0);
+ cairo_paint (s->cairo);
+
+ cairo_rectangle (s->cairo, video->x, video->y, video->w, video->h);
+
+ cairo_restore (s->cairo);
+}
+
+/*
+ * video_new:
+ * @filename:
+ * @x, @y: Position where to position the video
+ *
+ */
+Item *
+video_new (const char *filename, double x, double y)
+{
+ Video *video = g_new0 (Video, 1);
+ AVFormatParameters *ap;
+
+ video_init (video);
+
+ video->filename = g_strdup (filename);
+ video->x = x;
+ video->y = y;
+ video->video_frames = g_async_queue_new ();
+
+ //
+ // Prepare separate thread
+ //
+ video->video_mutex = g_mutex_new ();
+ pipe (video->pipe);
+ fcntl (video->pipe [0], F_SETFL, O_NONBLOCK);
+
+ g_io_add_watch (g_io_channel_unix_new (video->pipe [0]),
+ G_IO_IN,
+ video_ready,
+ video);
+
+ // Start decoding thread
+ video->decode_thread_id = g_thread_create (decoder, video, TRUE, NULL);
+
+ return (Item *) video;
+}
+
+void
+video_destroy (Video *video)
+{
+ g_free (video->video_rgb_buffer);
+ cairo_surface_destroy (video->video_cairo_surface);
+
+ g_free (video->filename);
+ g_free (video);
+}
+
+
Property changes on: trunk/moon/src/video.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/moon/src/video.cpp
===================================================================
--- trunk/moon/src/video.cpp 2007-05-25 21:24:02 UTC (rev 77978)
+++ trunk/moon/src/video.cpp 2007-05-25 22:11:36 UTC (rev 77979)
@@ -0,0 +1,122 @@
+#define __STDC_LIMIT_MACROS 1
+#include <string.h>
+#include <gtk/gtk.h>
+#include <cairo.h>
+#include <malloc.h>
+#include <glib.h>
+#include <stdlib.h>
+#include "runtime.h"
+
+// video specific
+#include <stdint.h>
+#include <avcodec.h>
+#include <avformat.h>
+
+typedef enum {
+ VIDEO_OK,
+ VIDEO_ERROR_OPEN,
+ VIDEO_ERROR_STREAM_INFO
+} VideoError;
+
+struct _Video {
+ Item item;
+ double x, y, w, h;
+ char *filename;
+
+ int error;
+
+ AVFormatContext av_format_context;
+};
+
+static void
+video_render (Item *item, Surface *s, double *affine, int x, int y, int width,
int height)
+{
+
+}
+
+static void
+video_getbounds (Item *item)
+{
+ Video *video = (Video *) item;
+ double res [6];
+ double *affine = item_affine_get_absolute (item, res);
+
+ Surface *s = item_surface_get (item);
+ if (s == NULL){
+ // not yet attached
+ return;
+ }
+
+ cairo_save (s->cairo);
+ if (affine != NULL)
+ cairo_set_matrix (s->cairo, (cairo_matrix_t *) affine);
+
+ cairo_rectangle (s->cairo, video->x, video->y, video->x + video->w,
video->y + video->h);
+ cairo_fill_extents (s->cairo, &item->x1, &item->y1, &item->x2,
&item->y2);
+ cairo_restore (s->cairo);
+}
+
+static ItemVtable video_vtable = { &video_render, &video_getbounds };
+
+static int video_inited;
+
+void
+video_init (Video *video)
+{
+ Item *item = &video->item;
+ item_init (item);
+ item->vtable = &video_vtable;
+
+ if (!video_inited){
+ avcodec_init ();
+ avcodec_register_all ();
+ video_inited = TRUE;
+ }
+}
+
+Item *
+video_new (const char *filename, double x, double y, double w, double h)
+{
+ Video *video = g_new (Video, 1);
+ AVFormatParameters *ap;
+
+ video_init (video);
+
+ video->filename = g_strdup (filename);
+ video->x = x;
+ video->y = y;
+ video->w = w;
+ video->h = h;
+
+ // avcodec setup
+ // auto-detect format
+ // default buffer size
+ // no additional parameters
+ if (av_open_input_file (&video->av_format_context, filename, NULL, 0,
NULL) < 0){
+ video->error = VIDEO_ERROR_OPEN;
+ return (Item *) video;
+ }
+ if (video->av_format_context == &rtsp_demuxer){
+ fprintf (stderr, "ERROR: This is a RTSP stream, handle it");
+ exit (1);
+ }
+
+ av_read_play (video->av_format_context);
+
+ if (av_find_stream_info(video->av_format_context) < 0){
+ video->error = VIDEO_ERROR_STREAM_INFO;
+ return (Item *) video;
+ }
+
+ printf ("OK\n");
+ return (Item *) video;
+}
+
+void
+video_destroy (Video *video)
+{
+ g_free (video->filename);
+ g_free (video);
+}
+
+
Property changes on: trunk/moon/src/video.cpp
___________________________________________________________________
Name: svn:eol-style
+ native
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches