summaryrefslogtreecommitdiffstats
path: root/xine_artsplugin
diff options
context:
space:
mode:
Diffstat (limited to 'xine_artsplugin')
-rw-r--r--xine_artsplugin/Makefile.am25
-rw-r--r--xine_artsplugin/audio_fifo_out.c407
-rw-r--r--xine_artsplugin/audio_fifo_out.h44
-rw-r--r--xine_artsplugin/configure.in.in257
-rw-r--r--xine_artsplugin/tools/Makefile.am1
-rw-r--r--xine_artsplugin/tools/thumbnail/Makefile.am24
-rw-r--r--xine_artsplugin/tools/thumbnail/sprocket-large.pngbin0 -> 1033 bytes
-rw-r--r--xine_artsplugin/tools/thumbnail/sprocket-medium.pngbin0 -> 649 bytes
-rw-r--r--xine_artsplugin/tools/thumbnail/sprocket-small.pngbin0 -> 357 bytes
-rw-r--r--xine_artsplugin/tools/thumbnail/videocreator.cpp376
-rw-r--r--xine_artsplugin/tools/thumbnail/videocreator.h40
-rw-r--r--xine_artsplugin/tools/thumbnail/videoscaler.cpp258
-rw-r--r--xine_artsplugin/tools/thumbnail/videoscaler.h24
-rw-r--r--xine_artsplugin/tools/thumbnail/videothumbnail.desktop71
-rw-r--r--xine_artsplugin/xineAudioPlayObject.mcopclass7
-rw-r--r--xine_artsplugin/xinePlayObject.idl13
-rw-r--r--xine_artsplugin/xinePlayObject.mcopclass7
-rw-r--r--xine_artsplugin/xinePlayObject_impl.cpp784
-rw-r--r--xine_artsplugin/xinePlayObject_impl.h158
-rw-r--r--xine_artsplugin/xineVideoPlayObject.mcopclass7
20 files changed, 2503 insertions, 0 deletions
diff --git a/xine_artsplugin/Makefile.am b/xine_artsplugin/Makefile.am
new file mode 100644
index 00000000..799bff29
--- /dev/null
+++ b/xine_artsplugin/Makefile.am
@@ -0,0 +1,25 @@
+INCLUDES= -I$(kde_includes)/arts $(all_includes) $(XINE_CFLAGS)
+
+AM_CFLAGS = -U__STRICT_ANSI__
+
+lib_LTLIBRARIES = libarts_xine.la
+
+libarts_xine_la_SOURCES = xinePlayObject.cc \
+ xinePlayObject_impl.cpp \
+ audio_fifo_out.c
+libarts_xine_la_LDFLAGS = $(all_libraries) -module -no-undefined -pthread
+libarts_xine_la_LIBADD = $(XINE_LIBS) $(LIB_X11) $(LIB_XEXT) \
+ -lkmedia2_idl -lsoundserver_idl -lartsflow
+
+libarts_xine_la_METASOURCES = AUTO
+
+$(srcdir)/xinePlayObject_impl.cpp: xinePlayObject.h
+xinePlayObject.cc xinePlayObject.h: $(srcdir)/xinePlayObject.idl
+ $(MCOPIDL) -I$(kde_includes)/arts $(srcdir)/xinePlayObject.idl
+
+noinst_HEADERS = xinePlayObject_impl.h audio_fifo_out.h
+
+mcopclassdir = $(libdir)/mcop
+mcopclass_DATA = xineAudioPlayObject.mcopclass xineVideoPlayObject.mcopclass
+
+SUBDIRS = tools
diff --git a/xine_artsplugin/audio_fifo_out.c b/xine_artsplugin/audio_fifo_out.c
new file mode 100644
index 00000000..eb5e24bc
--- /dev/null
+++ b/xine_artsplugin/audio_fifo_out.c
@@ -0,0 +1,407 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002-2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ 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.1 of the License, or (at your option) any later version.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+#include <xine/audio_out.h>
+
+#include "audio_fifo_out.h"
+
+#define GAP_TOLERANCE 5000
+
+typedef struct fifo_driver_s
+{
+ ao_driver_t ao_driver;
+
+ xine_arts_audio *audio;
+
+ int capabilities;
+ int mode;
+ pthread_mutex_t read_mutex;
+ pthread_mutex_t write_mutex;
+ pthread_cond_t cond;
+
+ uint32_t bytes_per_frame;
+ uint8_t *fifo;
+ int fifo_size;
+ int fifo_read_ptr;
+ int fifo_write_ptr;
+ int fifo_flush;
+ int fifo_delay;
+} fifo_driver_t;
+
+/*
+ * open the audio device for writing to
+ */
+static int ao_fifo_open( ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)this_gen;
+
+ if ((mode & ao->capabilities) == 0)
+ {
+ fprintf( stderr, "fifo_audio_out: unsupported mode %08x\n", mode);
+ return 0;
+ }
+
+ /* lock read buffer */
+ pthread_mutex_lock( &ao->read_mutex );
+
+ ao->mode = mode;
+ ao->audio->sample_rate = rate;
+ ao->audio->bits_per_sample = bits;
+
+ switch (mode)
+ {
+ case AO_CAP_MODE_MONO:
+ ao->audio->num_channels = 1;
+ break;
+ case AO_CAP_MODE_STEREO:
+ ao->audio->num_channels = 2;
+ break;
+ }
+
+ ao->bytes_per_frame = (ao->audio->bits_per_sample * ao->audio->num_channels) / 8;
+ ao->fifo_size = ao->audio->sample_rate * ao->bytes_per_frame;
+ ao->fifo = malloc( 2*ao->fifo_size );
+ ao->fifo_read_ptr = 0;
+ ao->fifo_write_ptr = 0;
+ ao->fifo_flush = 0;
+ ao->fifo_delay = 0;
+
+ /* unlock and enable read buffer for aRts sound server */
+ pthread_mutex_unlock( &ao->read_mutex );
+
+ return ao->audio->sample_rate;
+}
+
+static int ao_fifo_num_channels( ao_driver_t *this_gen )
+{
+ return ((fifo_driver_t *)this_gen)->audio->num_channels;
+}
+
+static int ao_fifo_bytes_per_frame( ao_driver_t *this_gen )
+{
+ return ((fifo_driver_t *)this_gen)->bytes_per_frame;
+}
+
+static int ao_fifo_get_gap_tolerance( ao_driver_t *this_gen )
+{
+ return GAP_TOLERANCE;
+}
+
+static int ao_fifo_bytes_in_buffer( fifo_driver_t *ao )
+{
+ int bytes_in_buffer = (ao->fifo_write_ptr - ao->fifo_read_ptr);
+
+ if (bytes_in_buffer < 0)
+ {
+ bytes_in_buffer += ao->fifo_size;
+ }
+ return bytes_in_buffer;
+}
+
+static int ao_fifo_write( ao_driver_t *this_gen, int16_t *data, uint32_t num_frames )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)this_gen;
+ uint8_t *src = (uint8_t *)data;
+ int bytes_in_buffer, bytes_to_write, written;
+
+ bytes_to_write = (num_frames * ao->bytes_per_frame);
+
+ pthread_mutex_lock( &ao->write_mutex );
+
+ while (!ao->fifo_flush && bytes_to_write > 0)
+ {
+ bytes_in_buffer = ao_fifo_bytes_in_buffer( ao );
+ written = bytes_to_write;
+
+ if ((bytes_in_buffer + written) >= ao->fifo_size)
+ {
+ written = (ao->fifo_size - bytes_in_buffer - 1);
+ written -= (written % ao->bytes_per_frame);
+
+ if (written == 0)
+ {
+ struct timespec ts;
+ struct timeval tv;
+ int delay;
+
+ gettimeofday( &tv, 0 );
+
+ delay = ao_fifo_arts_delay();
+ delay += (1000 * num_frames) / ao->audio->sample_rate;
+ delay = (delay < 20) ? 20 : ((delay >= 250) ? 250 : delay + 1);
+
+ ts.tv_sec = tv.tv_sec + (delay / 1000);
+ ts.tv_nsec = (1000 * tv.tv_usec) + (1000000 * (delay % 1000));
+
+ if (ts.tv_nsec >= 1000000000)
+ {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000;
+ }
+ if (pthread_cond_timedwait( &ao->cond, &ao->write_mutex, &ts ) != 0)
+ {
+ fprintf( stderr, "fifo_audio_out: blocked for more than %d ms,\n", delay);
+ fprintf( stderr, "fifo_audio_out: %d sample(s) discarded.\n", num_frames);
+ pthread_mutex_unlock( &ao->write_mutex );
+ return 0;
+ }
+ }
+ }
+
+ if (!ao->fifo_flush && written > 0)
+ {
+ int new_write_ptr = (ao->fifo_write_ptr + written);
+
+ if (new_write_ptr >= ao->fifo_size)
+ {
+ new_write_ptr -= ao->fifo_size;
+
+ memcpy( &ao->fifo[ao->fifo_write_ptr], src, (written - new_write_ptr) );
+ memcpy( ao->fifo, &src[written - new_write_ptr], new_write_ptr );
+ }
+ else
+ {
+ memcpy( &ao->fifo[ao->fifo_write_ptr], src, written );
+ }
+
+ /* update audio buffer pointer */
+ ao->fifo_write_ptr = new_write_ptr;
+ bytes_to_write -= written;
+ src += written;
+ }
+ }
+
+ /* audio has stopped */
+ ao->fifo_delay += bytes_to_write;
+
+ pthread_mutex_unlock( &ao->write_mutex );
+
+ return 1;
+}
+
+static int ao_fifo_delay( ao_driver_t *this_gen )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)this_gen;
+ return (ao_fifo_arts_delay() * ao->audio->sample_rate / 1000)
+ + ((ao_fifo_bytes_in_buffer( ao ) + ao->fifo_delay) / ao->bytes_per_frame);
+}
+
+static void ao_fifo_close( ao_driver_t *this_gen )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)this_gen;
+
+ /* lock read buffer */
+ pthread_mutex_lock( &ao->read_mutex );
+
+ /* disable audio driver */
+ ao->fifo_flush = 2;
+ ao->fifo_delay = 0;
+
+ /* free audio FIFO */
+ if (ao->fifo)
+ {
+ free( ao->fifo );
+ ao->fifo = NULL;
+ }
+ pthread_mutex_unlock( &ao->read_mutex );
+}
+
+static uint32_t ao_fifo_get_capabilities( ao_driver_t *this_gen )
+{
+ return ((fifo_driver_t *)this_gen)->capabilities;
+}
+
+static void ao_fifo_exit( ao_driver_t *this_gen )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)this_gen;
+
+ ao_fifo_close( this_gen );
+
+ pthread_cond_destroy( &ao->cond );
+ pthread_mutex_destroy( &ao->read_mutex );
+ pthread_mutex_destroy( &ao->write_mutex );
+
+ free( ao );
+}
+
+static int ao_fifo_get_property( ao_driver_t *this_gen, int property )
+{
+ return 0;
+}
+
+static int ao_fifo_set_property( ao_driver_t *this_gen, int property, int value )
+{
+ return ~value;
+}
+
+static int ao_fifo_control( ao_driver_t *this_gen, int cmd, ... )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)this_gen;
+
+ switch (cmd)
+ {
+ case AO_CTRL_FLUSH_BUFFERS:
+ case AO_CTRL_PLAY_PAUSE:
+ /* flush audio FIFO */
+ pthread_mutex_lock( &ao->read_mutex );
+
+ ao->fifo_read_ptr = ao->fifo_write_ptr;
+
+ if (ao->fifo_flush == 1)
+ {
+ ao->fifo_flush = 0;
+ ao->fifo_delay = 0;
+ }
+ pthread_mutex_unlock( &ao->read_mutex );
+
+ break;
+
+ case AO_CTRL_PLAY_RESUME:
+ break;
+ }
+ return 0;
+}
+
+xine_audio_port_t *init_audio_out_plugin( xine_t *xine, xine_arts_audio *audio,
+ void **ao_driver )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)malloc( sizeof(fifo_driver_t) );
+
+ ao->audio = audio;
+ ao->fifo = NULL;
+ ao->fifo_read_ptr = 0;
+ ao->fifo_write_ptr = 0;
+ ao->fifo_flush = 2;
+ ao->fifo_delay = 0;
+ ao->capabilities = (AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO);
+
+ ao->ao_driver.get_capabilities = ao_fifo_get_capabilities;
+ ao->ao_driver.get_property = ao_fifo_get_property;
+ ao->ao_driver.set_property = ao_fifo_set_property;
+ ao->ao_driver.open = ao_fifo_open;
+ ao->ao_driver.num_channels = ao_fifo_num_channels;
+ ao->ao_driver.bytes_per_frame = ao_fifo_bytes_per_frame;
+ ao->ao_driver.delay = ao_fifo_delay;
+ ao->ao_driver.write = ao_fifo_write;
+ ao->ao_driver.close = ao_fifo_close;
+ ao->ao_driver.exit = ao_fifo_exit;
+ ao->ao_driver.get_gap_tolerance = ao_fifo_get_gap_tolerance;
+ ao->ao_driver.control = ao_fifo_control;
+
+ pthread_cond_init( &ao->cond, NULL );
+ pthread_mutex_init( &ao->read_mutex, NULL );
+ pthread_mutex_init( &ao->write_mutex, NULL );
+
+ *ao_driver = (void *)ao;
+
+ return _x_ao_new_port( xine, (ao_driver_t *)ao, 0 );
+}
+
+unsigned long ao_fifo_read( void *ao_driver, unsigned char **buffer,
+ unsigned long samples )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)ao_driver;
+ int bytes_in_buffer, bytes_to_read;
+
+ /* lock read buffer */
+ pthread_mutex_lock( &ao->read_mutex );
+
+ bytes_in_buffer = ao_fifo_bytes_in_buffer( ao );
+ bytes_to_read = (samples * ao->bytes_per_frame);
+
+ if (ao->fifo_flush || bytes_in_buffer == 0)
+ {
+ /* unlock read buffer */
+ pthread_mutex_unlock( &ao->read_mutex );
+
+ /* signal blocked writes */
+ pthread_mutex_lock( &ao->write_mutex );
+ pthread_cond_signal( &ao->cond );
+ pthread_mutex_unlock( &ao->write_mutex );
+
+ /* audio FIFO empty or disabled, return */
+ return 0;
+ }
+
+ if (bytes_to_read > bytes_in_buffer)
+ {
+ fprintf( stderr, "fifo_audio_out: audio buffer underflow!\n" );
+ bytes_to_read = bytes_in_buffer - (bytes_in_buffer % ao->bytes_per_frame);
+ }
+ if ((ao->fifo_read_ptr + bytes_to_read) > ao->fifo_size)
+ {
+ /* copy samples from front to end of buffer */
+ memcpy( &ao->fifo[ao->fifo_size], ao->fifo,
+ ((ao->fifo_read_ptr + bytes_to_read) - ao->fifo_size) );
+ }
+
+ /* return pointer to audio samples */
+ *buffer = &ao->fifo[ao->fifo_read_ptr];
+
+ return bytes_to_read;
+}
+
+void ao_fifo_flush( void *ao_driver, unsigned long samples )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)ao_driver;
+ int bytes_in_buffer, bytes_to_flush;
+
+ /* flush audio data */
+ bytes_in_buffer = ao_fifo_bytes_in_buffer( ao );
+ bytes_to_flush = (samples * ao->bytes_per_frame);
+
+ if (bytes_to_flush <= bytes_in_buffer)
+ {
+ int new_read_ptr = (ao->fifo_read_ptr + bytes_to_flush);
+
+ if (new_read_ptr >= ao->fifo_size)
+ {
+ new_read_ptr -= ao->fifo_size;
+ }
+ ao->fifo_read_ptr = new_read_ptr;
+ }
+
+ /* unlock read buffer */
+ pthread_mutex_unlock( &ao->read_mutex );
+
+ /* signal blocked writes */
+ pthread_mutex_lock( &ao->write_mutex );
+ pthread_cond_signal( &ao->cond );
+ pthread_mutex_unlock( &ao->write_mutex );
+}
+
+void ao_fifo_clear( void *ao_driver, int clear )
+{
+ fifo_driver_t *ao = (fifo_driver_t *)ao_driver;
+
+ pthread_mutex_lock( &ao->write_mutex );
+
+ /* enable/disable audio driver */
+ ao->fifo_flush = clear;
+ ao->fifo_delay = 0;
+
+ if (clear)
+ {
+ /* signal blocked writes */
+ pthread_cond_signal( &ao->cond );
+ }
+ pthread_mutex_unlock( &ao->write_mutex );
+}
diff --git a/xine_artsplugin/audio_fifo_out.h b/xine_artsplugin/audio_fifo_out.h
new file mode 100644
index 00000000..b6629001
--- /dev/null
+++ b/xine_artsplugin/audio_fifo_out.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002-2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ 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.1 of the License, or (at your option) any later version.
+*/
+
+#ifndef __AUDIO_FIFO_OUT_H
+#define __AUDIO_FIFO_OUT_H
+
+#include <xine.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ int32_t sample_rate;
+ uint32_t num_channels;
+ uint32_t bits_per_sample;
+} xine_arts_audio;
+
+
+xine_audio_port_t *init_audio_out_plugin( xine_t *xine, xine_arts_audio *audio,
+ void **ao_driver );
+
+int ao_fifo_arts_delay();
+
+unsigned long ao_fifo_read( void *ao_driver, unsigned char **buffer,
+ unsigned long samples );
+
+void ao_fifo_flush( void *ao_driver, unsigned long samples );
+
+void ao_fifo_clear( void *ao_driver, int clear );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/xine_artsplugin/configure.in.in b/xine_artsplugin/configure.in.in
new file mode 100644
index 00000000..a79269b1
--- /dev/null
+++ b/xine_artsplugin/configure.in.in
@@ -0,0 +1,257 @@
+dnl Configure paths for XINE
+dnl
+dnl Copyright (C) 2001 Daniel Caujolle-Bert <segfault@club-internet.fr>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+dnl
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a configuration
+dnl script generated by Autoconf, you may include it under the same
+dnl distribution terms that you use for the rest of that program.
+dnl
+if test "x$build_arts" = "xno"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE xine_artsplugin"
+fi
+
+
+dnl AC_PATH_XINE([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for XINE, and define XINE_CFLAGS and XINE_LIBS
+dnl
+AC_DEFUN([AC_PATH_XINE],
+[dnl
+dnl Get the cflags and libraries from the xine-config script
+dnl
+AC_ARG_WITH(xine-prefix,
+ [ --with-xine-prefix=PFX Prefix where XINE is installed (optional)],
+ xine_config_prefix="$withval", xine_config_prefix="")
+AC_ARG_WITH(xine-exec-prefix,
+ [ --with-xine-exec-prefix=PFX Exec prefix where XINE is installed (optional)],
+ xine_config_exec_prefix="$withval", xine_config_exec_prefix="")
+AC_ARG_ENABLE(xinetest,
+ [ --disable-xinetest Do not try to compile and run a test XINE program],, enable_xinetest=yes)
+
+ if test x$xine_config_exec_prefix != x ; then
+ xine_config_args="$xine_config_args --exec-prefix=$xine_config_exec_prefix"
+ if test x${XINE_CONFIG+set} != xset ; then
+ XINE_CONFIG=$xine_config_exec_prefix/bin/xine-config
+ fi
+ fi
+ if test x$xine_config_prefix != x ; then
+ xine_config_args="$xine_config_args --prefix=$xine_config_prefix"
+ if test x${XINE_CONFIG+set} != xset ; then
+ XINE_CONFIG=$xine_config_prefix/bin/xine-config
+ fi
+ fi
+
+ min_xine_version=ifelse([$1], ,0.5.0,$1)
+ if test "x$enable_xinetest" != "xyes" ; then
+ AC_MSG_CHECKING([for XINE-LIB version >= $min_xine_version])
+ else
+ AC_PATH_PROG(XINE_CONFIG, xine-config, no)
+ AC_MSG_CHECKING([for XINE-LIB version >= $min_xine_version])
+ no_xine=""
+ if test "$XINE_CONFIG" = "no" ; then
+ no_xine=yes
+ else
+ XINE_CFLAGS=`$XINE_CONFIG $xine_config_args --cflags`
+ XINE_LIBS=`$XINE_CONFIG $xine_config_args --libs`
+ xine_config_major_version=`$XINE_CONFIG $xine_config_args --version | \
+ sed -n 's/^\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*$/\1/p'`
+ xine_config_minor_version=`$XINE_CONFIG $xine_config_args --version | \
+ sed -n 's/^\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*$/\2/p'`
+ xine_config_sub_version=`$XINE_CONFIG $xine_config_args --version | \
+ sed -n 's/^\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*$/\3/p'`
+ xine_script_dir=`$XINE_CONFIG $xine_config_args --scriptdir`
+ xine_plugin_dir=`$XINE_CONFIG $xine_config_args --plugindir`
+ xine_locale_dir=`$XINE_CONFIG $xine_config_args --localedir`
+ dnl if test "x$enable_xinetest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $XINE_CFLAGS $all_includes"
+ LIBS="$XINE_LIBS $LIBS $all_libraries"
+dnl
+dnl Now check if the installed XINE is sufficiently new. (Also sanity
+dnl checks the results of xine-config to some extent
+dnl
+ AC_LANG_SAVE()
+ AC_LANG_C()
+ rm -f conf.xinetest
+ AC_TRY_RUN([
+#include <xine.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main ()
+{
+ int major, minor, sub;
+ char *tmp_version;
+
+ system ("touch conf.xinetest");
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = (char *) strdup("$min_xine_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &sub) != 3) {
+ printf("%s, bad version string\n", "$min_xine_version");
+ exit(1);
+ }
+
+ if ((XINE_MAJOR_VERSION != $xine_config_major_version) ||
+ (XINE_MINOR_VERSION != $xine_config_minor_version) ||
+ (XINE_SUB_VERSION != $xine_config_sub_version))
+ {
+ printf("\n*** 'xine-config --version' returned %d.%d.%d, but XINE (%d.%d.%d)\n",
+ $xine_config_major_version, $xine_config_minor_version, $xine_config_sub_version,
+ XINE_MAJOR_VERSION, XINE_MINOR_VERSION, XINE_SUB_VERSION);
+ printf ("*** was found! If xine-config was correct, then it is best\n");
+ printf ("*** to remove the old version of XINE. You may also be able to fix the error\n");
+ printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+ printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+ printf("*** required on your system.\n");
+ printf("*** If xine-config was wrong, set the environment variable XINE_CONFIG\n");
+ printf("*** to point to the correct copy of xine-config, and remove the file config.cache\n");
+ printf("*** before re-running configure\n");
+ }
+ else
+ {
+ if ((XINE_MAJOR_VERSION > major) ||
+ ((XINE_MAJOR_VERSION == major) && (XINE_MINOR_VERSION > minor)) ||
+ ((XINE_MAJOR_VERSION == major) && (XINE_MINOR_VERSION == minor) && (XINE_SUB_VERSION >= sub)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** An old version of XINE (%d.%d.%d) was found.\n",
+ XINE_MAJOR_VERSION, XINE_MINOR_VERSION, XINE_SUB_VERSION);
+ printf("*** You need a version of XINE newer than %d.%d.%d. The latest version of\n",
+ major, minor, sub);
+ printf("*** XINE is always available from:\n");
+ printf("*** http://xine.sourceforge.net\n");
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the xine-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of XINE, but you can also set the XINE_CONFIG environment to point to the\n");
+ printf("*** correct copy of xine-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ }
+ return 1;
+}
+],, no_xine=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ if test "x$no_xine" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test "$XINE_CONFIG" = "no" ; then
+ echo "*** The xine-config script installed by XINE could not be found"
+ echo "*** If XINE was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the XINE_CONFIG environment variable to the"
+ echo "*** full path to xine-config."
+ else
+ if test -f conf.xinetest ; then
+ :
+ else
+ echo "*** Could not run XINE test program, checking why..."
+ CFLAGS="$CFLAGS $XINE_CFLAGS"
+ LIBS="$LIBS $XINE_LIBS"
+ AC_TRY_LINK([
+#include <xine.h>
+#include <stdio.h>
+], [ return ((XINE_MAJOR_VERSION) || (XINE_MINOR_VERSION) || (XINE_SUB_VERSION)); ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding XINE or finding the wrong"
+ echo "*** version of XINE. If it is not finding XINE, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ echo "***"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means XINE was incorrectly installed"
+ echo "*** or that you have moved XINE since it was installed. In the latter case, you"
+ echo "*** may want to edit the xine-config script: $XINE_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ XINE_CFLAGS=""
+ XINE_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(XINE_CFLAGS)
+ AC_SUBST(XINE_LIBS)
+ AC_LANG_RESTORE()
+ rm -f conf.xinetest
+
+dnl Make sure HAVE_STRSEP, HAVE_SETENV and HAVE_STRPBRK are defined as
+dnl necessary.
+ AC_CHECK_FUNCS([strsep strpbrk setenv])
+])
+
+dnl Check for XShmGetEventBase
+AC_MSG_CHECKING([for XShmGetEventBase])
+AC_LANG_SAVE()
+AC_LANG_CPLUSPLUS()
+AC_TRY_COMPILE([
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+ ],[
+static Display *display = NULL;
+int shmCompletionType = XShmGetEventBase( display );
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_XSHMGETEVENTBASE, 1, [Define if you have XShmGetEventBase in <X11/extensions/XShm.h])
+ ],[
+ AC_MSG_RESULT(no)
+ ]
+)
+AC_LANG_RESTORE()
+
+dnl Check for new internal xine symbol names
+KDE_CHECK_LIB(xine, _x_ao_new_port, :,
+[
+ AC_DEFINE(_x_ao_new_port, ao_new_port, [Compatibility with older version of xine])
+])
+AC_CHECK_FUNC([ao_new_port])
+
+AC_ARG_WITH([xine],
+ [AC_HELP_STRING([--with-xine],
+ [Enable support for Xine @<:@default=check@:>@])],
+ [], with_xine=check)
+
+have_xine=no
+if test "x$with_xine" != xno; then
+ AC_PATH_XINE(1.0.0, have_xine=yes)
+
+ if test "x$with_xine" != xcheck && test "x$have_xine" != xyes; then
+ AC_MSG_ERROR([--with-xine was given, but test for Xine failed])
+ fi
+fi
+
+if test "x$have_xine" != xyes; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE xine_artsplugin"
+fi
diff --git a/xine_artsplugin/tools/Makefile.am b/xine_artsplugin/tools/Makefile.am
new file mode 100644
index 00000000..1ed9efda
--- /dev/null
+++ b/xine_artsplugin/tools/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=thumbnail
diff --git a/xine_artsplugin/tools/thumbnail/Makefile.am b/xine_artsplugin/tools/thumbnail/Makefile.am
new file mode 100644
index 00000000..40358fda
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/Makefile.am
@@ -0,0 +1,24 @@
+## $Id$
+## Makefile.am of kdemultimedia/tools/thumbnail
+
+INCLUDES = -I$(kde_includes)/arts $(all_includes) $(XINE_CFLAGS)
+
+AM_CFLAGS = -U__STRICT_ANSI__
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = videothumbnail.la
+
+videothumbnail_la_SOURCES = videocreator.cpp videoscaler.cpp
+videothumbnail_la_LIBADD = $(XINE_LIBS) $(LIB_KDECORE)
+videothumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -pthread
+
+noinst_HEADERS = videocreator.h
+
+xineartsplugin_tools_videothumbnail_DATA = sprocket-small.png sprocket-medium.png sprocket-large.png
+
+xineartsplugin_tools_videothumbnaildir = $(kde_datadir)/videothumbnail
+
+services_DATA = videothumbnail.desktop
+
+servicesdir = $(kde_servicesdir)
diff --git a/xine_artsplugin/tools/thumbnail/sprocket-large.png b/xine_artsplugin/tools/thumbnail/sprocket-large.png
new file mode 100644
index 00000000..6c0e65a9
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/sprocket-large.png
Binary files differ
diff --git a/xine_artsplugin/tools/thumbnail/sprocket-medium.png b/xine_artsplugin/tools/thumbnail/sprocket-medium.png
new file mode 100644
index 00000000..8868e660
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/sprocket-medium.png
Binary files differ
diff --git a/xine_artsplugin/tools/thumbnail/sprocket-small.png b/xine_artsplugin/tools/thumbnail/sprocket-small.png
new file mode 100644
index 00000000..62fa3fd7
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/sprocket-small.png
Binary files differ
diff --git a/xine_artsplugin/tools/thumbnail/videocreator.cpp b/xine_artsplugin/tools/thumbnail/videocreator.cpp
new file mode 100644
index 00000000..94e87b48
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/videocreator.cpp
@@ -0,0 +1,376 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Simon MacMullen
+ Copyright (C) 2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ 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; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// $Id$
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include <qpixmap.h>
+#include <qdialog.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpaintdevice.h>
+
+#include <iostream>
+
+#include <kstandarddirs.h>
+#include <kapplication.h>
+
+#define XINE_ENABLE_EXPERIMENTAL_FEATURES 1
+
+#include <xine.h>
+
+#include "videocreator.h"
+#include "videoscaler.h"
+
+#define TIMEOUT 15 // 15 seconds
+#define MAX_ATTEMPTS 25
+
+
+// Global xine pointer
+static xine_t *xine_shared = NULL;
+static pthread_mutex_t xine_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t xine_cond = PTHREAD_COND_INITIALIZER;
+static int xineRefCount = 0;
+
+static void xine_init_routine()
+{
+ char cfgFileName[272];
+
+ xine_shared = (xine_t *)xine_new();
+
+ snprintf( cfgFileName, 272, "%s/.xine/config", getenv( "HOME" ) );
+
+ xine_config_load( xine_shared, (const char *)cfgFileName );
+
+ xine_init( xine_shared );
+}
+
+static void *xine_timeout_routine( void * )
+{
+ pthread_mutex_lock( &xine_mutex );
+
+ while (xine_shared != 0)
+ {
+ if (xineRefCount == 0)
+ {
+ struct timespec ts;
+ struct timeval tv;
+
+ gettimeofday( &tv, 0 );
+
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ ts.tv_sec += TIMEOUT;
+
+ if (pthread_cond_timedwait( &xine_cond, &xine_mutex, &ts ) != 0 &&
+ xineRefCount == 0)
+ {
+ xine_exit( xine_shared );
+ xine_shared = NULL;
+ break;
+ }
+ }
+ else
+ {
+ pthread_cond_wait( &xine_cond, &xine_mutex );
+ }
+ }
+ pthread_mutex_unlock( &xine_mutex );
+
+ return NULL;
+}
+
+static xine_t *xine_shared_init()
+{
+ pthread_mutex_lock( &xine_mutex );
+
+ ++xineRefCount;
+
+ if (xine_shared == 0)
+ {
+ pthread_t thread;
+
+ xine_init_routine();
+
+ if (pthread_create( &thread, NULL, xine_timeout_routine, NULL ) == 0)
+ {
+ pthread_detach( thread );
+ }
+ }
+ else
+ {
+ pthread_cond_signal( &xine_cond );
+ }
+ pthread_mutex_unlock( &xine_mutex );
+
+ return xine_shared;
+}
+
+static void xine_shared_exit( xine_t * )
+{
+ pthread_mutex_lock( &xine_mutex );
+
+ if (--xineRefCount == 0)
+ {
+ pthread_cond_signal( &xine_cond );
+ }
+ pthread_mutex_unlock( &xine_mutex );
+}
+
+static QImage createThumbnail( xine_video_frame_t *frame, int width, int height )
+{
+ unsigned char *base[3];
+ unsigned int pitches[3];
+
+ if ((frame->aspect_ratio * height) > width)
+ height = (int)(.5 + (width / frame->aspect_ratio));
+ else
+ width = (int)(.5 + (height * frame->aspect_ratio));
+
+ QImage image( width, height, 32 );
+
+ if (frame->colorspace == XINE_IMGFMT_YV12)
+ {
+ int y_size, uv_size;
+
+ pitches[0] = (frame->width + 7) & ~0x7;
+ pitches[1] = (((frame->width + 1) / 2) + 7) & ~0x7;
+ pitches[2] = pitches[1];
+
+ y_size = pitches[0] * frame->height;
+ uv_size = pitches[1] * ((frame->height + 1) / 2);
+
+ base[0] = frame->data;
+ base[1] = base[0] + y_size + uv_size;
+ base[2] = base[0] + y_size;
+
+ scaleYuvToRgb32( frame->width, frame->height, base, pitches,
+ width, height, (unsigned int *)image.bits(),
+ image.bytesPerLine() );
+ }
+ else if (frame->colorspace == XINE_IMGFMT_YUY2)
+ {
+ pitches[0] = 2*((frame->width + 3) & ~0x3);
+ base[0] = frame->data;
+
+ scaleYuy2ToRgb32( frame->width, frame->height, base[0], pitches[0],
+ width, height, (unsigned int *)image.bits(),
+ image.bytesPerLine() );
+ }
+ return image;
+}
+
+// Return the variance of the brightness of the pixels
+static double imageVariance( unsigned char *pixels, int pitch,
+ int width, int height, int step )
+{
+ double sigmaX = 0;
+ double sigmaXSquared = 0;
+
+ for (int y=0; y < height ; y++)
+ {
+ unsigned int uSigmaX = 0;
+ unsigned int uSigmaXSquared = 0;
+
+ for (int x=0, n=(width * step); x < n ; x+=step)
+ {
+ int gray = pixels[x];
+
+ uSigmaX += gray;
+ uSigmaXSquared += gray * gray;
+ }
+
+ sigmaX += uSigmaX;
+ sigmaXSquared += uSigmaXSquared;
+
+ pixels += pitch;
+ }
+
+ unsigned int total = height * width;
+
+ return sqrt( sigmaXSquared / total - (sigmaX / total) * (sigmaX / total) );
+}
+
+static bool findBestFrame( xine_video_port_t *vo_port, xine_video_frame_t *frame )
+{
+ xine_video_frame_t frames[2], *bestFrame = NULL;
+ double variance, bestVariance = 0;
+
+ for (int i=0, n=0; i < MAX_ATTEMPTS; i++)
+ {
+ xine_video_frame_t *cFrame = &frames[n];
+
+ // Try to read next frame
+ if (!xine_get_next_video_frame( vo_port, cFrame ))
+ {
+ break;
+ }
+
+ variance = imageVariance( cFrame->data, ((cFrame->width + 7) & ~0x7),
+ cFrame->width, cFrame->height,
+ (cFrame->colorspace == XINE_IMGFMT_YV12) ? 1 : 2 );
+
+ // Compare current frame to best frame
+ if (bestFrame == NULL || variance > bestVariance)
+ {
+ if (bestFrame != NULL)
+ {
+ xine_free_video_frame( vo_port, bestFrame );
+ }
+
+ bestFrame = cFrame;
+ bestVariance = variance;
+
+ n = (1 - n);
+ }
+ else
+ {
+ xine_free_video_frame( vo_port, cFrame );
+ }
+
+ // Stop searching if current frame is interesting enough
+ if (variance > 40.0)
+ {
+ break;
+ }
+ }
+
+ // This should be the best frame to create a thumbnail from
+ if (bestFrame != NULL)
+ {
+ *frame = *bestFrame;
+ }
+ return (bestFrame != NULL);
+}
+
+
+extern "C"
+{
+ ThumbCreator *new_creator()
+ {
+ return new VideoCreator;
+ }
+}
+
+VideoCreator::VideoCreator()
+{
+}
+
+VideoCreator::~VideoCreator()
+{
+}
+
+bool VideoCreator::create(const QString &path, int width, int height, QImage &img)
+{
+ if (m_sprocketSmall.isNull())
+ {
+ QString pixmap = locate( "data", "videothumbnail/sprocket-small.png" );
+ m_sprocketSmall = QPixmap(pixmap);
+ pixmap = locate( "data", "videothumbnail/sprocket-medium.png" );
+ m_sprocketMedium = QPixmap(pixmap);
+ pixmap = locate( "data", "videothumbnail/sprocket-large.png" );
+ m_sprocketLarge = QPixmap(pixmap);
+ }
+
+ // The long term plan is to seek to frame 1, create thumbnail, see if is is
+ // interesting enough, if not seek to frame 2, then 4, then 8, etc.
+ // "Interesting enough" means the variance of the pixel brightness is high. This
+ // is because many videos fade up from black and a black rectangle is boring.
+ //
+ // But for the time being we can't seek so we just let it play for one second
+ // then take whatever we find.
+
+ xine_t *xine = xine_shared_init();
+ xine_audio_port_t *ao_port = xine_new_framegrab_audio_port( xine );
+ xine_video_port_t *vo_port = xine_new_framegrab_video_port( xine );
+ xine_stream_t *stream = xine_stream_new( xine, ao_port, vo_port );
+ bool success = false;
+
+ if (xine_open( stream, QFile::encodeName ( path ).data() ))
+ {
+ xine_video_frame_t frame;
+ int length;
+
+ // Find 'best' (or at least any) frame
+ if (!xine_get_pos_length( stream, NULL, NULL, &length ) || length > 5000)
+ {
+ if (xine_play( stream, 0, 4000 ))
+ {
+ success = findBestFrame( vo_port, &frame );
+ }
+ }
+ if (!success)
+ {
+ // Some codecs can't seek to start, but close/open works
+ xine_close( stream );
+ xine_open( stream, path.ascii() );
+
+ if (xine_play( stream, 0, 0 ))
+ {
+ success = findBestFrame( vo_port, &frame );
+ }
+ }
+
+ // Create thumbnail image
+ if (success)
+ {
+ QPixmap pix( createThumbnail( &frame, width, height ) );
+ QPainter painter( &pix );
+ QPixmap sprocket;
+
+ if (pix.height() < 60)
+ sprocket = m_sprocketSmall;
+ else if (pix.height() < 90)
+ sprocket = m_sprocketMedium;
+ else
+ sprocket = m_sprocketLarge;
+
+ for (int y = 0; y < pix.height() + sprocket.height(); y += sprocket.height()) {
+ painter.drawPixmap( 0, y, sprocket );
+ }
+
+ img = pix.convertToImage();
+
+ xine_free_video_frame( vo_port, &frame );
+ }
+
+ xine_stop( stream );
+ }
+
+ xine_dispose( stream );
+ xine_close_audio_driver( xine, ao_port );
+ xine_close_video_driver( xine, vo_port );
+ xine_shared_exit( xine );
+
+ return (success);
+}
+
+ThumbCreator::Flags VideoCreator::flags() const
+{
+ return (ThumbCreator::Flags) (DrawFrame);
+}
+
+#include "videocreator.moc"
diff --git a/xine_artsplugin/tools/thumbnail/videocreator.h b/xine_artsplugin/tools/thumbnail/videocreator.h
new file mode 100644
index 00000000..bd16e6e2
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/videocreator.h
@@ -0,0 +1,40 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Simon MacMullen
+
+ 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; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _VIDEOCREATOR_H_
+#define _VIDEOCREATOR_H_ "$Id$"
+
+#include <kio/thumbcreator.h>
+
+class VideoCreator : public QObject, public ThumbCreator
+{
+ Q_OBJECT
+public:
+ VideoCreator();
+ virtual ~VideoCreator();
+ virtual bool create(const QString &path, int width, int height, QImage &img);
+ virtual Flags flags() const;
+
+private:
+ QPixmap m_sprocketSmall;
+ QPixmap m_sprocketMedium;
+ QPixmap m_sprocketLarge;
+};
+
+#endif
diff --git a/xine_artsplugin/tools/thumbnail/videoscaler.cpp b/xine_artsplugin/tools/thumbnail/videoscaler.cpp
new file mode 100644
index 00000000..2b4b49ad
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/videoscaler.cpp
@@ -0,0 +1,258 @@
+/*
+ This file is part of KDE/aRts - xine integration
+ Copyright (C) 2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ inspired by code from the xine project
+
+ Copyright (C) 2003 the xine project
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <config.h>
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include "videoscaler.h"
+
+#define THUMBNAIL_BRIGHTNESS +32
+#define THUMBNAIL_CONTRAST 128
+#define THUMBNAIL_SATURATION 128
+
+
+// Colorspace conversion tables
+static int tableLY[256];
+static int tableRV[256], tableBU[256], tableGU[256], tableGV[256];
+static int clipR[2240], clipG[2240], clipB[2240];
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+
+static void init_once_routine()
+{
+ int cly = ( 76309 * THUMBNAIL_CONTRAST + 64) / 128;
+ int crv = (104597 * THUMBNAIL_SATURATION + 64) / 128;
+ int cbu = (132201 * THUMBNAIL_SATURATION + 64) / 128;
+ int cgu = ( 25675 * THUMBNAIL_SATURATION + 64) / 128;
+ int cgv = ( 53279 * THUMBNAIL_SATURATION + 64) / 128;
+ int i;
+
+ for (i=0; i < 256; i++)
+ {
+ tableLY[i] = cly * (i + THUMBNAIL_BRIGHTNESS - 16) + (864 << 16) + 32768;
+ tableRV[i] = crv * (i - 128);
+ tableBU[i] = cbu * (i - 128);
+ tableGU[i] = cgu * (i - 128);
+ tableGV[i] = cgv * (i - 128);
+ }
+ for (i=0; i < 2240; i++)
+ {
+ int c = (i < 864) ? 0 : ((i > 1119) ? 255 : (i - 864));
+
+ clipR[i] = c << 16;
+ clipG[i] = c << 8;
+ clipB[i] = c;
+ }
+}
+
+static void yuvToRgb32( unsigned char *bufy, unsigned char *bufu, unsigned char *bufv,
+ unsigned int *pixels, int width )
+{
+ for (int i=0; i < width; i++)
+ {
+ int l = tableLY[bufy[i]];
+
+ pixels[i] = clipR[(l + tableRV[bufv[i]]) >> 16] |
+ clipG[(l - tableGU[bufu[i]] - tableGV[bufv[i]]) >> 16] |
+ clipB[(l + tableBU[bufu[i]]) >> 16];
+ }
+}
+
+static inline void scaleLine( unsigned char *src[2], int width,
+ unsigned char *dst, int scaledWidth,
+ int scale, int weight, int step, int offset )
+{
+ int a, b, c, d;
+ int x = (scale / 2) - 32768;
+ unsigned char *p0 = (src[0] + offset);
+ unsigned char *p1 = (src[1] + offset);
+
+ weight >>= 8;
+
+ if (scaledWidth > width)
+ {
+ /* Trailing pixels, no horizontal filtering */
+ c = scaledWidth - (((width << 16) - 32768 - (scale / 2)) / scale);
+ a = p0[(step * width) - step];
+ b = p1[(step * width) - step];
+ a += (128 + (b - a) * weight) >> 8;
+ scaledWidth -= c;
+ memset( &dst[scaledWidth], a, c );
+
+ /* Leading pixels, no horizontal filtering */
+ c = (32767 + (scale / 2)) / scale;
+ a = p0[0];
+ b = p1[0];
+ a += (128 + (b - a) * weight) >> 8;
+ scaledWidth -= c;
+ memset( dst, a, c );
+
+ /* Adjust source and destination */
+ dst += c;
+ x += (c * scale);
+ }
+
+ for (int i=0; i < scaledWidth; i++)
+ {
+ int xhi = (step == 1) ? (x >> 16)
+ : ((step == 2) ? (x >> 15) & ~0x1
+ : (x >> 14) & ~0x3);
+ int xlo = (x & 0xFFFF) >> 8;
+
+ /* Four nearest points for bilinear filtering */
+ a = p0[xhi];
+ b = p0[xhi + step];
+ c = p1[xhi];\
+ d = p1[xhi + step];
+
+ /* Interpolate horizontally */
+ a = (256 * a) + (b - a) * xlo;
+ c = (256 * c) + (d - c) * xlo;
+
+ /* Interpolate vertically and store bilinear filtered sample */
+ *(dst++) = ((256 * a) + (c - a) * weight + 32768) >> 16;
+
+ x += scale;
+ }
+}
+
+void scaleYuvToRgb32( int width, int height,
+ unsigned char *base[3], unsigned int pitches[3],
+ int scaledWidth, int scaledHeight,
+ unsigned int *pixels, unsigned int bytesPerLine )
+{
+ int chromaWidth = (width + 1) / 2;
+ int chromaHeight = (height + 1) / 2;
+ int scaleX = (width << 16) / scaledWidth;
+ int scaleY = (height << 16) / scaledHeight;
+ int scaleCX = (scaleX / 2);
+ int y = (scaleY / 2) - 32768;
+
+ // Temporary line buffers (stack)
+ unsigned char *bufy = (unsigned char *)alloca( scaledWidth );
+ unsigned char *bufu = (unsigned char *)alloca( scaledWidth );
+ unsigned char *bufv = (unsigned char *)alloca( scaledWidth );
+
+ pthread_once( &once_control, init_once_routine );
+
+ for (int i=0; i < scaledHeight; i++)
+ {
+ unsigned char *twoy[2], *twou[2], *twov[2];
+ int y2 = (y / 2) - 32768;
+
+ // Calculate luminance scanlines for bilinear filtered scaling
+ if (y < 0)
+ {
+ twoy[0] = twoy[1] = base[0];
+ }
+ else if (y >= ((height - 1) << 16))
+ {
+ twoy[0] = twoy[1] = base[0] + (height - 1) * pitches[0];
+ }
+ else
+ {
+ twoy[0] = base[0] + (y >> 16) * pitches[0];
+ twoy[1] = twoy[0] + pitches[0];
+ }
+
+ // Calculate chrominance scanlines for bilinear filtered scaling
+ if (y2 < 0)
+ {
+ twou[0] = twou[1] = base[1];
+ twov[0] = twov[1] = base[2];
+ }
+ else if (y2 >= ((chromaHeight - 1) << 16))
+ {
+ twou[0] = twou[1] = base[1] + (chromaHeight - 1) * pitches[1];
+ twov[0] = twov[1] = base[2] + (chromaHeight - 1) * pitches[2];
+ }
+ else
+ {
+ twou[0] = base[1] + (y2 >> 16) * pitches[1];
+ twov[0] = base[2] + (y2 >> 16) * pitches[2];
+ twou[1] = twou[0] + pitches[1];
+ twov[1] = twov[0] + pitches[2];
+ }
+
+ // Bilinear filtered scaling
+ scaleLine( twoy, width, bufy, scaledWidth, scaleX, (y & 0xFFFF), 1, 0 );
+ scaleLine( twou, chromaWidth, bufu, scaledWidth, scaleCX, (y2 & 0xFFFF), 1, 0 );
+ scaleLine( twov, chromaWidth, bufv, scaledWidth, scaleCX, (y2 & 0xFFFF), 1, 0 );
+
+ // YUV to RGB32 comnversion
+ yuvToRgb32( bufy, bufu, bufv, pixels, scaledWidth );
+
+ pixels = (unsigned int *)(((char *)pixels) + bytesPerLine);
+ y += scaleY;
+ }
+}
+
+void scaleYuy2ToRgb32( int width, int height,
+ unsigned char *base, unsigned int pitch,
+ int scaledWidth, int scaledHeight,
+ unsigned int *pixels, unsigned int bytesPerLine )
+{
+ int chromaWidth = (width + 1) / 2;
+ int scaleX = (width << 16) / scaledWidth;
+ int scaleY = (height << 16) / scaledHeight;
+ int scaleCX = (scaleX / 2);
+ int y = (scaleY / 2) - 32768;
+
+ // Temporary line buffers (stack)
+ unsigned char *bufy = (unsigned char *)alloca( scaledWidth );
+ unsigned char *bufu = (unsigned char *)alloca( scaledWidth );
+ unsigned char *bufv = (unsigned char *)alloca( scaledWidth );
+
+ pthread_once( &once_control, init_once_routine );
+
+ for (int i=0; i < scaledHeight; i++)
+ {
+ unsigned char *two[2];
+
+ // Calculate scanlines for bilinear filtered scaling
+ if (y < 0)
+ {
+ two[0] = two[1] = base;
+ }
+ else if (y >= ((height - 1) << 16))
+ {
+ two[0] = two[1] = base + (height - 1) * pitch;
+ }
+ else
+ {
+ two[0] = base + (y >> 16) * pitch;
+ two[1] = two[0] + pitch;
+ }
+
+ // Bilinear filtered scaling
+ scaleLine( two, width, bufy, scaledWidth, scaleX, (y & 0xFFFF), 2, 0 );
+ scaleLine( two, chromaWidth, bufu, scaledWidth, scaleCX, (y & 0xFFFF), 4, 1 );
+ scaleLine( two, chromaWidth, bufv, scaledWidth, scaleCX, (y & 0xFFFF), 4, 3 );
+
+ // YUV to RGB32 comnversion
+ yuvToRgb32( bufy, bufu, bufv, pixels, scaledWidth );
+
+ pixels = (unsigned int *)(((char *)pixels) + bytesPerLine);
+ y += scaleY;
+ }
+}
diff --git a/xine_artsplugin/tools/thumbnail/videoscaler.h b/xine_artsplugin/tools/thumbnail/videoscaler.h
new file mode 100644
index 00000000..fd4d51db
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/videoscaler.h
@@ -0,0 +1,24 @@
+/*
+ This file is part of KDE/aRts - xine integration
+ Copyright (C) 2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+*/
+
+#ifndef __VIDEOSCALER_H
+#define __VIDEOSCALER_H
+
+void scaleYuvToRgb32( int width, int height,
+ unsigned char *base[3], unsigned int pitches[3],
+ int scaledWidth, int scaledHeight,
+ unsigned int *pixels, unsigned int bytesPerLine );
+
+void scaleYuy2ToRgb32( int width, int height,
+ unsigned char *base, unsigned int pitch,
+ int scaledWidth, int scaledHeight,
+ unsigned int *pixels, unsigned int bytesPerLine );
+
+#endif
diff --git a/xine_artsplugin/tools/thumbnail/videothumbnail.desktop b/xine_artsplugin/tools/thumbnail/videothumbnail.desktop
new file mode 100644
index 00000000..e437b2a3
--- /dev/null
+++ b/xine_artsplugin/tools/thumbnail/videothumbnail.desktop
@@ -0,0 +1,71 @@
+[Desktop Entry]
+Type=Service
+Name=Video Files
+Name[af]=Video Lêers
+Name[ar]=ملفات مرئيات
+Name[bg]=Видео файлове
+Name[bn]=ভিডিও ফাইল
+Name[br]=Restroù Video
+Name[bs]=Video datoteke
+Name[ca]=Fitxers de vídeo
+Name[cs]=Video soubory
+Name[cy]=Ffeiliau Fideo
+Name[da]=Videofiler
+Name[de]=Video-Dateien
+Name[el]=Αρχεία βίντεο
+Name[eo]=Vidaj dosieroj
+Name[es]=Archivos de vídeo
+Name[et]=Videofailid
+Name[eu]=Bideo fitxategiak
+Name[fa]=پرونده‌های ویدیویی
+Name[fi]=Videotiedostot
+Name[fr]=Fichiers vidéo
+Name[ga]=Comhaid Fhíse
+Name[gl]=Ficheiros de Video
+Name[he]=קבצי וידאו
+Name[hi]=वीडियो फ़ाइलें
+Name[hr]=Video datoteke
+Name[hu]=Videófájlok
+Name[is]=Kvikmyndaskrár
+Name[it]=File Video
+Name[ja]=ビデオファイル
+Name[kk]=Бейне файлдар
+Name[km]=ឯកសារ​វីដេអូ
+Name[ko]=비디오 파일
+Name[lt]=Video bylos
+Name[mk]=Видео датотеки
+Name[nb]=Videofiler
+Name[nds]=Videodateien
+Name[ne]=भिडियो फाइल
+Name[nl]=Videobestanden
+Name[nn]=Videofiler
+Name[pa]=ਵੀਡਿਓ ਫਾਇਲਾਂ
+Name[pl]=Pliki wideo
+Name[pt]=Ficheiros de Vídeo
+Name[pt_BR]=Arquivos de vídeo
+Name[ro]=Fişiere video
+Name[ru]=Видеофайлы
+Name[sk]=Video súbory
+Name[sl]=Video datoteke
+Name[sr]=Видео фајлови
+Name[sr@Latn]=Video fajlovi
+Name[sv]=Videofiler
+Name[ta]=படக்காட்சி கோப்புகள்
+Name[tg]=Файлҳои Видео
+Name[th]=แฟ้มวิดีโอ
+Name[tr]=Video Dosyaları
+Name[uk]=Відеофайли
+Name[uz]=Video fayllar
+Name[uz@cyrillic]=Видео файллар
+Name[ven]=Dzifaela dza Video
+Name[wa]=Fitchîs videyo
+Name[xh]=Iifayile ze Video
+Name[zh_CN]=视频文件
+Name[zh_HK]=視訊檔案
+Name[zh_TW]=視訊檔案
+Name[zu]=Amafayela Evidiyo
+ServiceTypes=ThumbCreator
+MimeTypes=video/*,application/vnd.ms-asf,application/vnd.rn-realmedia
+X-KDE-Library=videothumbnail
+CacheThumbnail=true
+IgnoreMaximumSize=true
diff --git a/xine_artsplugin/xineAudioPlayObject.mcopclass b/xine_artsplugin/xineAudioPlayObject.mcopclass
new file mode 100644
index 00000000..5a2f2225
--- /dev/null
+++ b/xine_artsplugin/xineAudioPlayObject.mcopclass
@@ -0,0 +1,7 @@
+Interface=xinePlayObject,Arts::PlayObject,Arts::SynthModule
+Author=Ewald Snel <ewald@rambo.its.tudelft.nl>
+Extension=flac,m4a,spx,ac3,aac,ogg,mp1,mp2,mp3,ra,wma,mpc,mp+
+MimeType=audio/vnd.rn-realaudio,audio/x-pn-realaudio,audio/x-flac,audio/x-oggflac,audio/x-speex,audio/mp4,audio/ac3,audio/aac,audio/vorbis,audio/x-mp3,audio/x-mp1,audio/x-mp2,audio/mpeg,audio/x-ms-wma,audio/x-musepack
+Language=C++
+Library=libarts_xine.la
+Preference=4
diff --git a/xine_artsplugin/xinePlayObject.idl b/xine_artsplugin/xinePlayObject.idl
new file mode 100644
index 00000000..7ba429d6
--- /dev/null
+++ b/xine_artsplugin/xinePlayObject.idl
@@ -0,0 +1,13 @@
+#include <kmedia2.idl>
+#include <soundserver.idl>
+
+interface xinePlayObject : Arts::PlayObject, Arts::SynthModule
+{
+ out audio stream left, right;
+};
+
+interface xineAudioPlayObject : xinePlayObject, Arts::PlayObject, Arts::SynthModule
+{};
+
+interface xineVideoPlayObject : xinePlayObject, Arts::PlayObject, Arts::VideoPlayObject, Arts::SynthModule
+{};
diff --git a/xine_artsplugin/xinePlayObject.mcopclass b/xine_artsplugin/xinePlayObject.mcopclass
new file mode 100644
index 00000000..21536a78
--- /dev/null
+++ b/xine_artsplugin/xinePlayObject.mcopclass
@@ -0,0 +1,7 @@
+Interface=xinePlayObject,Arts::PlayObject,Arts::VideoPlayObject,Arts::SynthModule,Arts::Object
+Author=Ewald Snel <ewald@rambo.its.tudelft.nl>
+Extension=vob,mpg,mpeg,m1v,m2v,m1s,m2s,m2p,avi,asf,asx,wmv,qt,mov,moov,mp4,rv,ra,ram,rm,smi,flac,m4v,m4a,spx,ac3,aac
+MimeType=video/x-mpg,video/x-dat,video/x-mpeg,video/mpeg,video/x-msvideo,video/x-ms-asf,video/x-ms-wmv,video/quicktime,video/x-theora,video/mp4,video/x-ogm,application/vnd.ms-asf,application/vnd.rn-realmedia,video/vnd.rn-realvideo,audio/vnd.rn-realaudio,audio/x-pn-realaudio,audio/x-flac,audio/x-speex,audio/mp4,audio/ac3,audio/aac,audio/vorbis,audio/x-mp3,audio/x-mp1,audio/x-mp2,audio/mpeg
+Language=C++
+Library=libarts_xine.la
+Preference=4
diff --git a/xine_artsplugin/xinePlayObject_impl.cpp b/xine_artsplugin/xinePlayObject_impl.cpp
new file mode 100644
index 00000000..21e3dff5
--- /dev/null
+++ b/xine_artsplugin/xinePlayObject_impl.cpp
@@ -0,0 +1,784 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002-2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ 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.1 of the License, or (at your option) any later version.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <math.h>
+#include <sys/time.h>
+#include <audiosubsys.h>
+#include <convert.h>
+#include <debug.h>
+
+#include "xinePlayObject_impl.h"
+
+#ifndef HAVE_XSHMGETEVENTBASE
+extern "C" {
+extern int XShmGetEventBase( Display* );
+};
+#endif
+
+#define TIMEOUT 15 // 15 seconds
+
+using namespace Arts;
+
+
+// Global xine pointer
+static xine_t *xine_shared = NULL;
+static pthread_mutex_t xine_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t xine_cond = PTHREAD_COND_INITIALIZER;
+static int xineRefCount = 0;
+static bool xineForceXShm = false;
+
+static void xine_init_routine()
+{
+ const char *id;
+ char cfgFileName[272];
+
+ xine_shared = (xine_t *)xine_new();
+
+ snprintf( cfgFileName, 272, "%s/.xine/config", getenv( "HOME" ) );
+
+ xine_config_load( xine_shared, (const char *)cfgFileName );
+
+ // Check default video output driver
+ id = xine_config_register_string (xine_shared, "video.driver",
+ "auto", "video driver to use",
+ NULL, 10, NULL, NULL);
+
+ xineForceXShm = (id && !strcasecmp( id, "XShm" ));
+
+ xine_init( xine_shared );
+}
+
+static void *xine_timeout_routine( void * )
+{
+ pthread_mutex_lock( &xine_mutex );
+
+ while (xine_shared != 0)
+ {
+ if (xineRefCount == 0)
+ {
+ struct timespec ts;
+ struct timeval tv;
+
+ gettimeofday( &tv, 0 );
+
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ ts.tv_sec += TIMEOUT;
+
+ if (pthread_cond_timedwait( &xine_cond, &xine_mutex, &ts ) != 0 &&
+ xineRefCount == 0)
+ {
+ xine_exit( xine_shared );
+ xine_shared = NULL;
+ break;
+ }
+ }
+ else
+ {
+ pthread_cond_wait( &xine_cond, &xine_mutex );
+ }
+ }
+ pthread_mutex_unlock( &xine_mutex );
+
+ return NULL;
+}
+
+static xine_t *xine_shared_init()
+{
+ pthread_mutex_lock( &xine_mutex );
+
+ ++xineRefCount;
+
+ if (xine_shared == 0)
+ {
+ pthread_t thread;
+
+ xine_init_routine();
+
+ if (pthread_create( &thread, NULL, xine_timeout_routine, NULL ) == 0)
+ {
+ pthread_detach( thread );
+ }
+ }
+ else
+ {
+ pthread_cond_signal( &xine_cond );
+ }
+ pthread_mutex_unlock( &xine_mutex );
+
+ return xine_shared;
+}
+
+static void xine_shared_exit( xine_t * )
+{
+ pthread_mutex_lock( &xine_mutex );
+
+ if (--xineRefCount == 0)
+ {
+ pthread_cond_signal( &xine_cond );
+ }
+ pthread_mutex_unlock( &xine_mutex );
+}
+
+int ao_fifo_arts_delay()
+{
+ return (int)(1000 * Arts::AudioSubSystem::the()->outputDelay());
+}
+
+xinePlayObject_impl::xinePlayObject_impl(bool audioOnly)
+ : mrl( "" ), xine( 0 ), stream( 0 ), queue( 0 ), ao_port( 0 ), vo_port( 0 ), audioOnly(audioOnly)
+{
+
+ if (!audioOnly)
+ {
+ XInitThreads();
+
+ if (!(display = XOpenDisplay( NULL )))
+ {
+ arts_fatal( "could not open X11 display" );
+ }
+
+ XFlush( display );
+
+ // Create a special window for uninterrupted X11 communication
+ xcomWindow = XCreateSimpleWindow( display, DefaultRootWindow( display ),
+ 0, 0, 1, 1, 0, 0, 0 );
+
+ XSelectInput( display, xcomWindow, ExposureMask );
+ }
+ pthread_mutex_init( &mutex, 0 );
+
+ if (!audioOnly)
+ {
+ // Initialize X11 properties
+ xcomAtomQuit = XInternAtom( display, "VPO_INTERNAL_EVENT", False );
+ xcomAtomResize = XInternAtom( display, "VPO_RESIZE_NOTIFY", False );
+ screen = DefaultScreen( display );
+ shmCompletionType = (XShmQueryExtension( display ) == True)
+ ? XShmGetEventBase( display ) + ShmCompletion : -1;
+
+ width = 0;
+ height = 0;
+ dscbTimeOut = 0;
+
+ // Initialize xine visual structure
+ visual.display = display;
+ visual.screen = screen;
+ visual.d = xcomWindow;
+ visual.dest_size_cb = &dest_size_cb;
+ visual.frame_output_cb = &frame_output_cb;
+ visual.user_data = this;
+ }
+
+ // Initialize audio and video details
+ Arts::SoundServerV2 server = Arts::Reference( "global:Arts_SoundServerV2" );
+ audio.sample_rate = 0;
+ audio.num_channels = 0;
+ audio.bits_per_sample = 0;
+
+ flpos = 0.0;
+ if (!audioOnly)
+ if (pthread_create( &thread, 0, pthread_start_routine, this ))
+ {
+ arts_fatal( "could not create thread" );
+ }
+}
+
+xinePlayObject_impl::~xinePlayObject_impl()
+{
+ XEvent event;
+
+ halt();
+
+ // Send stop event to thread (X11 client message)
+ memset( &event, 0, sizeof(event) );
+
+ event.type = ClientMessage;
+ event.xclient.window = xcomWindow;
+ event.xclient.message_type = xcomAtomQuit;
+ event.xclient.format = 32;
+
+ if (!audioOnly)
+ {
+
+ XSendEvent( display, xcomWindow, True, 0, &event );
+
+ XFlush( display );
+
+ // Wait for the thread to die
+ pthread_join( thread, 0 );
+
+ }
+
+ // Destroy stream, xine and related resources
+ if (stream != 0)
+ {
+ halt();
+
+ xine_event_dispose_queue( queue );
+ xine_dispose( stream );
+ xine_close_audio_driver( xine, ao_port );
+ xine_close_video_driver( xine, vo_port );
+ }
+ if (xine != 0)
+ {
+ xine_shared_exit( xine );
+ }
+
+ pthread_mutex_destroy( &mutex );
+
+ if (!audioOnly)
+ {
+ XSync( display, False );
+ XDestroyWindow( display, xcomWindow );
+ XCloseDisplay( display );
+ }
+}
+
+bool xinePlayObject_impl::loadMedia( const string &url )
+{
+ bool result = false;
+
+ pthread_mutex_lock( &mutex );
+
+ mrl = "";
+
+ if (stream == 0)
+ {
+ if (xine == 0)
+ {
+ xine = xine_shared_init();
+ }
+
+ ao_port = init_audio_out_plugin( xine, &audio, &ao_driver );
+
+ if (xineForceXShm && !audioOnly)
+ {
+ vo_port = xine_open_video_driver( xine, "XShm",
+ XINE_VISUAL_TYPE_X11,
+ (void *)&visual );
+ }
+ if (vo_port == 0 && !audioOnly)
+ {
+ vo_port = xine_open_video_driver( xine, "Xv",
+ XINE_VISUAL_TYPE_X11,
+ (void *)&visual );
+ }
+ if (vo_port == 0 && !audioOnly)
+ {
+ vo_port = xine_open_video_driver( xine, "XShm",
+ XINE_VISUAL_TYPE_X11,
+ (void *)&visual );
+ }
+ if (vo_port == 0 && !audioOnly)
+ {
+ vo_port = xine_open_video_driver( xine, "OpenGL",
+ XINE_VISUAL_TYPE_X11,
+ (void *)&visual );
+ }
+ if (vo_port == 0)
+ {
+ vo_port = xine_open_video_driver( xine, 0,
+ XINE_VISUAL_TYPE_NONE, 0 );
+ }
+
+ if (ao_port != 0 && vo_port != 0 )
+ {
+ stream = xine_stream_new( xine, ao_port, vo_port );
+
+ if (stream != 0)
+ {
+ xine_set_param( stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, 0 );
+ xine_set_param( stream, XINE_PARAM_SPU_CHANNEL, -1 );
+
+ queue = xine_event_new_queue( stream );
+ xine_event_create_listener_thread( queue, xine_handle_event, this );
+ }
+ }
+ if (stream == 0)
+ {
+ if (ao_port != 0)
+ {
+ xine_close_audio_driver( xine, ao_port );
+ ao_port = 0;
+ }
+ if (vo_port != 0)
+ {
+ xine_close_video_driver( xine, vo_port );
+ vo_port = 0;
+ }
+ }
+ }
+
+ if (stream != 0)
+ {
+ if (xine_get_status( stream ) == XINE_STATUS_PLAY)
+ {
+ ao_fifo_clear( ao_driver, 2 );
+
+ xine_stop( stream );
+
+ clearWindow();
+ }
+ if ((result = xine_open( stream, url.c_str() )))
+ {
+ mrl = url;
+ }
+
+ streamLength = 0;
+ streamPosition = 0;
+
+ width = 0;
+ height = 0;
+ }
+
+ pthread_mutex_unlock( &mutex );
+
+ return result;
+}
+
+string xinePlayObject_impl::description()
+{
+ return "xine aRts plugin";
+}
+
+poTime xinePlayObject_impl::currentTime()
+{
+ poTime time;
+ int pos_time;
+
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0 && !mrl.empty())
+ {
+ if (xine_get_pos_length( stream, 0, &pos_time, 0 ))
+ {
+ streamPosition = pos_time;
+ }
+ else
+ {
+ pos_time = streamPosition;
+ }
+
+ time.seconds = pos_time / 1000;
+ time.ms = pos_time % 1000;
+ }
+ else
+ {
+ time.seconds = 0;
+ time.ms = 0;
+ }
+ pthread_mutex_unlock( &mutex );
+
+ return time;
+}
+
+poTime xinePlayObject_impl::overallTime()
+{
+ poTime time;
+ int length_time;
+
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0 && !mrl.empty())
+ {
+ if (xine_get_pos_length( stream, 0, 0, &length_time ))
+ {
+ streamLength = length_time;
+ }
+ else
+ {
+ length_time = streamLength;
+ }
+
+ if (length_time <= 0)
+ {
+ length_time = 1;
+ }
+
+ time.seconds = length_time / 1000;
+ time.ms = length_time % 1000;
+ }
+ else
+ {
+ time.seconds = 0;
+ time.ms = 1;
+ }
+ pthread_mutex_unlock( &mutex );
+
+ return time;
+}
+
+poCapabilities xinePlayObject_impl::capabilities()
+{
+ int n;
+
+ pthread_mutex_lock( &mutex );
+
+ n = (stream == 0) ? 0 : xine_get_stream_info( stream, XINE_STREAM_INFO_SEEKABLE );
+
+ pthread_mutex_unlock( &mutex );
+
+ return static_cast<poCapabilities>( capPause | ((n == 0) ? 0 : capSeek) );
+}
+
+string xinePlayObject_impl::mediaName()
+{
+ return mrl;
+}
+
+poState xinePlayObject_impl::state()
+{
+ poState state;
+
+ pthread_mutex_lock( &mutex );
+
+ if (stream == 0 || xine_get_status( stream ) != XINE_STATUS_PLAY)
+ state = posIdle;
+ else if (xine_get_param( stream, XINE_PARAM_SPEED ) == XINE_SPEED_PAUSE)
+ state = posPaused;
+ else
+ state = posPlaying;
+
+ pthread_mutex_unlock( &mutex );
+
+ return state;
+}
+
+void xinePlayObject_impl::play()
+{
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0)
+ {
+ if (xine_get_status( stream ) == XINE_STATUS_PLAY)
+ {
+ if (xine_get_param( stream, XINE_PARAM_SPEED ) == XINE_SPEED_PAUSE)
+ {
+ xine_set_param( stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL );
+ }
+ }
+ else if (!mrl.empty())
+ {
+ xine_play( stream, 0, 0 );
+ }
+ }
+ pthread_mutex_unlock( &mutex );
+}
+
+void xinePlayObject_impl::halt()
+{
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0 && xine_get_status( stream ) == XINE_STATUS_PLAY)
+ {
+ ao_fifo_clear( ao_driver, 2 );
+
+ xine_stop( stream );
+
+ clearWindow();
+
+ streamLength = 0;
+ streamPosition = 0;
+ }
+ pthread_mutex_unlock( &mutex );
+}
+
+void xinePlayObject_impl::seek( const class poTime &t )
+{
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0 && xine_get_status( stream ) == XINE_STATUS_PLAY)
+ {
+ int seekPosition = (1000 * t.seconds) + t.ms;
+ int paused = (xine_get_param( stream, XINE_PARAM_SPEED ) == XINE_SPEED_PAUSE);
+
+ ao_fifo_clear( ao_driver, 1 );
+
+ if (xine_play( stream, 0, seekPosition ))
+ {
+ if (seekPosition >= 0 && seekPosition <= streamLength)
+ {
+ streamPosition = seekPosition;
+ }
+ }
+
+ if (paused)
+ {
+ xine_set_param( stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE );
+ }
+
+ ao_fifo_clear( ao_driver, 0 );
+ }
+ pthread_mutex_unlock( &mutex );
+}
+
+void xinePlayObject_impl::pause()
+{
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0 && xine_get_status( stream ) == XINE_STATUS_PLAY)
+ {
+ ao_fifo_clear( ao_driver, 1 );
+
+ xine_set_param( stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE );
+ }
+ pthread_mutex_unlock( &mutex );
+}
+
+void xinePlayObject_impl::calculateBlock( unsigned long samples )
+{
+ unsigned int skip, received = 0, converted = 0, xSamples = 0;
+ unsigned char *buffer;
+ double speed = 1.0;
+
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0)
+ {
+ // Calculate resampling parameters
+ speed = (double)audio.sample_rate / samplingRateFloat;
+ xSamples = (unsigned int)((double)samples * speed + 8.0);
+ received = ao_fifo_read( ao_driver, &buffer, xSamples );
+ }
+
+ pthread_mutex_unlock( &mutex );
+
+ // Convert samples and fill gaps with zeroes
+ if (received)
+ {
+ converted = uni_convert_stereo_2float( samples, buffer, received,
+ audio.num_channels,
+ audio.bits_per_sample,
+ left, right, speed, flpos );
+ flpos += (double)converted * speed;
+ skip = (int)floor( flpos );
+ skip = (received < (xSamples - 8)) ? (xSamples - 8) : skip;
+ flpos = flpos - floor( flpos );
+ ao_fifo_flush( ao_driver, skip );
+ }
+ for (unsigned long i=converted; i < samples; i++)
+ {
+ left[i] = 0;
+ right[i] = 0;
+ }
+}
+
+void xinePlayObject_impl::xineEvent( const xine_event_t &event )
+{
+ if (event.type == XINE_EVENT_UI_PLAYBACK_FINISHED)
+ {
+ clearWindow();
+ }
+}
+
+void xinePlayObject_impl::clearWindow()
+{
+ if (audioOnly) return;
+
+ Window root;
+ unsigned int u, w, h;
+ int x, y, screen;
+
+ XLockDisplay( display );
+
+ screen = DefaultScreen( display );
+
+ XGetGeometry( display, visual.d, &root, &x, &y, &w, &h, &u, &u );
+
+ XSetForeground( display, DefaultGC( display, screen ),
+ BlackPixel( display, screen ) );
+ XFillRectangle( display, visual.d,
+ DefaultGC( display, screen ), x, y, w, h );
+
+ XUnlockDisplay( display );
+}
+
+void xinePlayObject_impl::frameOutput( int &x, int &y,
+ int &width, int &height, double &ratio,
+ int displayWidth, int displayHeight,
+ double displayPixelAspect, bool dscb )
+{
+ if (audioOnly) return;
+
+ Window child, root;
+ unsigned int u;
+ int n;
+
+ XLockDisplay( display );
+
+ XGetGeometry( display, visual.d, &root, &n, &n,
+ (unsigned int *)&width, (unsigned int *)&height, &u, &u );
+
+ if (!dscb)
+ {
+ XTranslateCoordinates( display, visual.d, root, 0, 0, &x, &y, &child );
+ }
+
+ // Most displays use (nearly) square pixels
+ ratio = 1.0;
+
+ // Correct for display pixel aspect
+ if (displayPixelAspect < 1.0)
+ {
+ displayHeight = (int)((displayHeight / displayPixelAspect) + .5);
+ }
+ else
+ {
+ displayWidth = (int)((displayWidth * displayPixelAspect) + .5);
+ }
+
+ if (dscb || dscbTimeOut == 0 || --dscbTimeOut == 0)
+ {
+ // Notify client of new display size
+ if (displayWidth != this->width || displayHeight != this->height)
+ {
+ this->width = displayWidth;
+ this->height = displayHeight;
+
+ resizeNotify();
+ }
+
+ // Reset 'seen dest_size_cb' time out
+ if (dscb)
+ {
+ dscbTimeOut = 25;
+ }
+ }
+ XUnlockDisplay( display );
+}
+
+void xinePlayObject_impl::resizeNotify()
+{
+ if (audioOnly) return;
+ XEvent event;
+
+ // Resize notify signal for front-ends
+ memset( &event, 0, sizeof(event) );
+
+ event.type = ClientMessage;
+ event.xclient.window = visual.d;
+ event.xclient.message_type = xcomAtomResize;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = width;
+ event.xclient.data.l[1] = height;
+
+ XSendEvent( display, visual.d, True, 0, &event );
+
+ XFlush( display );
+}
+
+void xinePlayObject_impl::eventLoop()
+{
+ XEvent event;
+
+ do
+ {
+ XNextEvent( display, &event );
+
+ if (event.type == Expose && event.xexpose.count == 0 &&
+ event.xexpose.window == visual.d)
+ {
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0)
+ {
+ xine_gui_send_vo_data( stream,
+ XINE_GUI_SEND_EXPOSE_EVENT,
+ &event );
+ }
+ else
+ {
+ clearWindow();
+ }
+ pthread_mutex_unlock( &mutex );
+ }
+ else if (event.type == shmCompletionType)
+ {
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0)
+ {
+ xine_gui_send_vo_data( stream,
+ XINE_GUI_SEND_COMPLETION_EVENT,
+ &event );
+ }
+ pthread_mutex_unlock( &mutex );
+ }
+ }
+ while (event.type != ClientMessage ||
+ event.xclient.message_type != xcomAtomQuit ||
+ event.xclient.window != xcomWindow);
+}
+
+void xineVideoPlayObject_impl::x11WindowId( long window )
+{
+ pthread_mutex_lock( &mutex );
+
+ if (window == -1)
+ {
+ window = xcomWindow;
+ }
+
+ if ((Window)window != visual.d)
+ {
+ XLockDisplay( display );
+
+ // Change window and set event mask of new window
+ visual.d = window;
+
+ XSelectInput( display, window, ExposureMask );
+
+ if (stream != 0)
+ {
+ resizeNotify();
+
+ xine_gui_send_vo_data( stream,
+ XINE_GUI_SEND_DRAWABLE_CHANGED,
+ (void *)window );
+ }
+
+ XUnlockDisplay( display );
+ }
+ pthread_mutex_unlock( &mutex );
+}
+
+long xineVideoPlayObject_impl::x11WindowId()
+{
+ return (visual.d == xcomWindow) ? (long)-1 : visual.d;
+}
+
+long xineVideoPlayObject_impl::x11Snapshot()
+{
+ long pixmap = -1;
+
+ pthread_mutex_lock( &mutex );
+
+ if (stream != 0 && xine_get_status( stream ) == XINE_STATUS_PLAY)
+ {
+ // FIXME: snapshot...
+ pixmap = (long)-1;
+ }
+ pthread_mutex_unlock( &mutex );
+
+ return pixmap;
+}
+
+REGISTER_IMPLEMENTATION(xinePlayObject_impl);
+REGISTER_IMPLEMENTATION(xineAudioPlayObject_impl);
+REGISTER_IMPLEMENTATION(xineVideoPlayObject_impl);
diff --git a/xine_artsplugin/xinePlayObject_impl.h b/xine_artsplugin/xinePlayObject_impl.h
new file mode 100644
index 00000000..94482dac
--- /dev/null
+++ b/xine_artsplugin/xinePlayObject_impl.h
@@ -0,0 +1,158 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002-2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ 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.1 of the License, or (at your option) any later version.
+*/
+
+#ifndef __XINEPLAYOBJECT_IMPL_H
+#define __XINEPLAYOBJECT_IMPL_H
+
+#include <string>
+#include <pthread.h>
+#include <stdsynthmodule.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+#include <xine.h>
+
+#include "audio_fifo_out.h"
+#include "xinePlayObject.h"
+
+
+using namespace std;
+using Arts::poState;
+using Arts::poTime;
+using Arts::poCapabilities;
+
+class xinePlayObject_impl : virtual public xinePlayObject_skel, public Arts::StdSynthModule
+{
+public:
+ xinePlayObject_impl(bool audioOnly=false);
+ virtual ~xinePlayObject_impl();
+
+ bool loadMedia( const string &url );
+ string description();
+ poTime currentTime();
+ poTime overallTime();
+ poCapabilities capabilities();
+ string mediaName();
+ poState state();
+ void play();
+ void halt();
+ void seek( const class poTime &t );
+ void pause();
+ void calculateBlock( unsigned long samples );
+
+protected:
+ void xineEvent( const xine_event_t &event );
+ void clearWindow();
+ void frameOutput( int &x, int &y,
+ int &width, int &height, double &ratio,
+ int displayWidth, int displayHeight,
+ double displayPixelAspect, bool dscb );
+ void resizeNotify();
+ void eventLoop();
+
+ // C -> C++ wrapper for pthread API
+ static inline void *pthread_start_routine( void *obj )
+ {
+ ((xinePlayObject_impl *)obj)->eventLoop();
+ pthread_exit( 0 );
+ }
+
+ // C -> C++ wrapper for xine API
+ static inline void xine_handle_event( void *obj, const xine_event_t *event )
+ {
+ ((xinePlayObject_impl *)obj)->xineEvent( *event );
+ }
+
+ // C -> C++ wrapper for xine API
+ static inline void frame_output_cb( void *obj,
+ int video_width, int video_height,
+ double video_pixel_aspect,
+ int *dest_x, int *dest_y,
+ int *dest_width, int *dest_height,
+ double *dest_pixel_aspect,
+ int *win_x, int *win_y )
+ {
+ ((xinePlayObject_impl *)obj)->frameOutput( *win_x, *win_y,
+ *dest_width, *dest_height,
+ *dest_pixel_aspect,
+ video_width, video_height,
+ video_pixel_aspect, false );
+
+ *dest_x = 0;
+ *dest_y = 0;
+ }
+
+ // C -> C++ wrapper for xine API
+ static inline void dest_size_cb( void *obj,
+ int video_width, int video_height,
+ double video_pixel_aspect,
+ int *dest_width, int *dest_height,
+ double *dest_pixel_aspect )
+ {
+ int win_x, win_y;
+
+ ((xinePlayObject_impl *)obj)->frameOutput( win_x, win_y,
+ *dest_width, *dest_height,
+ *dest_pixel_aspect,
+ video_width, video_height,
+ video_pixel_aspect, true );
+ }
+
+private:
+ double flpos;
+ string mrl;
+
+protected:
+ pthread_mutex_t mutex;
+ pthread_t thread;
+
+ // xine data
+ xine_t *xine;
+ xine_stream_t *stream;
+ xine_event_queue_t *queue;
+ xine_audio_port_t *ao_port;
+ xine_video_port_t *vo_port;
+ void *ao_driver;
+ x11_visual_t visual;
+ xine_arts_audio audio;
+
+ Display *display;
+ Window xcomWindow;
+ Atom xcomAtomQuit;
+ Atom xcomAtomResize;
+ int screen;
+ int width;
+ int height;
+ int dscbTimeOut;
+ int shmCompletionType;
+
+private:
+ int streamLength;
+ int streamPosition;
+ bool audioOnly;
+};
+
+class xineAudioPlayObject_impl : virtual public xineAudioPlayObject_skel, public xinePlayObject_impl
+{
+public:
+ xineAudioPlayObject_impl() : xinePlayObject_impl(true) {};
+};
+
+class xineVideoPlayObject_impl : virtual public xineVideoPlayObject_skel, public xinePlayObject_impl
+{
+public:
+ xineVideoPlayObject_impl() : xinePlayObject_impl(false) {};
+ long x11Snapshot();
+ long x11WindowId();
+ void x11WindowId( long window );
+};
+
+
+#endif
diff --git a/xine_artsplugin/xineVideoPlayObject.mcopclass b/xine_artsplugin/xineVideoPlayObject.mcopclass
new file mode 100644
index 00000000..5863fcf1
--- /dev/null
+++ b/xine_artsplugin/xineVideoPlayObject.mcopclass
@@ -0,0 +1,7 @@
+Interface=xinePlayObject,Arts::PlayObject,Arts::VideoPlayObject,Arts::SynthModule
+Author=Ewald Snel <ewald@rambo.its.tudelft.nl>
+Extension=vob,mpg,mpeg,m1v,m2v,m4v,m1s,m2s,m2p,avi,asf,asx,wmv,qt,mov,moov,mp4,rv,ram,rm,smi,ogm
+MimeType=video/x-mpg,video/x-dat,video/x-mpeg,video/mpeg,video/x-msvideo,video/x-ms-asf,video/x-ms-wmv,video/quicktime,video/x-theora,video/mp4,video/x-ogm,application/vnd.ms-asf,application/vnd.rn-realmedia,video/vnd.rn-realvideo,application/ogg
+Language=C++
+Library=libarts_xine.la
+Preference=4