|
|
|
/* This file is part of the KMPlayer application
|
|
|
|
Copyright (C) 2003 Koos Vriezen <koos.vriezen@xs4all.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.
|
|
|
|
|
|
|
|
This program 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
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <libgen.h>
|
|
|
|
#include <dcopclient.h>
|
|
|
|
#include <tqcstring.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqurl.h>
|
|
|
|
#include <tqthread.h>
|
|
|
|
#include <tqmutex.h>
|
|
|
|
#include <tqdom.h>
|
|
|
|
#include "kmplayer_backend.h"
|
|
|
|
#include "kmplayer_callback_stub.h"
|
|
|
|
#include "kmplayer_callback.h"
|
|
|
|
#include "xineplayer.h"
|
|
|
|
#include <X11/X.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <X11/extensions/XShm.h>
|
|
|
|
|
|
|
|
#include <xine.h>
|
|
|
|
#include <xine/xineutils.h>
|
|
|
|
|
|
|
|
#ifndef XShmGetEventBase
|
|
|
|
extern int XShmGetEventBase(Display *);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MWM_HINTS_DECORATIONS (1L << 1)
|
|
|
|
#define PROP_MWM_HINTS_ELEMENTS 5
|
|
|
|
typedef struct {
|
|
|
|
uint32_t flags;
|
|
|
|
uint32_t functions;
|
|
|
|
uint32_t decorations;
|
|
|
|
int32_t input_mode;
|
|
|
|
uint32_t status;
|
|
|
|
} MWMHints;
|
|
|
|
|
|
|
|
|
|
|
|
static KXinePlayer * xineapp;
|
|
|
|
static KMPlayer::Callback_stub * callback;
|
|
|
|
static TQMutex mutex (true);
|
|
|
|
|
|
|
|
static xine_t *xine;
|
|
|
|
static xine_stream_t *stream;
|
|
|
|
static xine_stream_t *sub_stream;
|
|
|
|
static xine_video_port_t *vo_port;
|
|
|
|
static xine_audio_port_t *ao_port;
|
|
|
|
static xine_post_t *post_plugin;
|
|
|
|
static xine_event_queue_t *event_queue;
|
|
|
|
static xine_cfg_entry_t audio_vis_cfg_entry;
|
|
|
|
static x11_visual_t vis;
|
|
|
|
static char configfile[2048];
|
|
|
|
static Atom quit_atom;
|
|
|
|
|
|
|
|
static Display *display;
|
|
|
|
static Window wid;
|
|
|
|
static bool window_created;
|
|
|
|
static bool xine_verbose;
|
|
|
|
static bool xine_vverbose;
|
|
|
|
static bool wants_config;
|
|
|
|
static bool audio_vis;
|
|
|
|
static int screen;
|
|
|
|
static int completion_event;
|
|
|
|
static int repeat_count;
|
|
|
|
static int xpos, ypos, width, height;
|
|
|
|
static int movie_width, movie_height, movie_length, movie_pos;
|
|
|
|
static int movie_brightness = 32767;
|
|
|
|
static int movie_contrast = 32767;
|
|
|
|
static int movie_hue = 32767;
|
|
|
|
static int movie_saturation = 32767;
|
|
|
|
static int movie_volume = 32767;
|
|
|
|
static double pixel_aspect;
|
|
|
|
|
|
|
|
static int running = 0;
|
|
|
|
static volatile int firstframe = 0;
|
|
|
|
static const int event_finished = TQEvent::User;
|
|
|
|
static const int event_progress = TQEvent::User + 2;
|
|
|
|
static const int event_url = TQEvent::User + 3;
|
|
|
|
static const int event_size = TQEvent::User + 4;
|
|
|
|
static const int event_title = TQEvent::User + 5;
|
|
|
|
static const int event_video = TQEvent::User + 6;
|
|
|
|
static TQString mrl;
|
|
|
|
static TQString sub_mrl;
|
|
|
|
static TQString rec_mrl;
|
|
|
|
static TQString alang, slang;
|
|
|
|
static TQStringList alanglist, slanglist;
|
|
|
|
|
|
|
|
static TQString elmentry ("entry");
|
|
|
|
static TQString elmitem ("item");
|
|
|
|
static TQString attname ("name");
|
|
|
|
static TQString atttype ("type");
|
|
|
|
static TQString attdefault ("DEFAULT");
|
|
|
|
static TQString attvalue ("value");
|
|
|
|
static TQString attstart ("START");
|
|
|
|
static TQString attend ("end");
|
|
|
|
static TQString valrange ("range");
|
|
|
|
static TQString valnum ("num");
|
|
|
|
static TQString valbool ("bool");
|
|
|
|
static TQString valenum ("enum");
|
|
|
|
static TQString valstring ("string");
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
static void dest_size_cb(void * /*data*/, int /*video_width*/, int /*video_height*/, double /*video_pixel_aspect*/,
|
|
|
|
int *dest_width, int *dest_height, double *dest_pixel_aspect) {
|
|
|
|
|
|
|
|
*dest_width = width;
|
|
|
|
*dest_height = height;
|
|
|
|
*dest_pixel_aspect = pixel_aspect;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void frame_output_cb(void * /*data*/, 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) {
|
|
|
|
if (running && firstframe) {
|
|
|
|
firstframe = 0;
|
|
|
|
int pos;
|
|
|
|
fprintf(stderr, "first frame\n");
|
|
|
|
mutex.lock ();
|
|
|
|
xine_get_pos_length (stream, 0, &pos, &movie_length);
|
|
|
|
movie_width = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_WIDTH);
|
|
|
|
movie_height = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
|
|
|
|
mutex.unlock ();
|
|
|
|
TQApplication::postEvent (xineapp, new XineMovieParamEvent (movie_length, movie_width, movie_height, alanglist, slanglist, true));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
*dest_x = 0;
|
|
|
|
*dest_y = 0;
|
|
|
|
*win_x = xpos;
|
|
|
|
*win_y = ypos;
|
|
|
|
*dest_width = width;
|
|
|
|
*dest_height = height;
|
|
|
|
*dest_pixel_aspect = pixel_aspect;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xine_config_cb (void * /*user_data*/, xine_cfg_entry_t * entry) {
|
|
|
|
fprintf (stderr, "xine_config_cb %s\n", entry->enum_values[entry->num_value]);
|
|
|
|
if (!stream)
|
|
|
|
return;
|
|
|
|
mutex.lock ();
|
|
|
|
if (post_plugin) {
|
|
|
|
xine_post_wire_audio_port (xine_get_audio_source (stream), ao_port);
|
|
|
|
xine_post_dispose (xine, post_plugin);
|
|
|
|
post_plugin = 0L;
|
|
|
|
}
|
|
|
|
if (audio_vis && strcmp (entry->enum_values[entry->num_value], "none")) {
|
|
|
|
post_plugin = xine_post_init (xine, entry->enum_values[entry->num_value], 0, &ao_port, &vo_port);
|
|
|
|
xine_post_wire (xine_get_audio_source (stream), (xine_post_in_t *) xine_post_input (post_plugin, (char *) "audio in"));
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void event_listener(void * /*user_data*/, const xine_event_t *event) {
|
|
|
|
if (event->stream != stream)
|
|
|
|
return; // not interested in sub_stream events
|
|
|
|
switch(event->type) {
|
|
|
|
case XINE_EVENT_UI_PLAYBACK_FINISHED:
|
|
|
|
fprintf (stderr, "XINE_EVENT_UI_PLAYBACK_FINISHED\n");
|
|
|
|
if (repeat_count-- > 0)
|
|
|
|
xine_play (stream, 0, 0);
|
|
|
|
else
|
|
|
|
TQApplication::postEvent (xineapp, new TQEvent ((TQEvent::Type) event_finished));
|
|
|
|
break;
|
|
|
|
case XINE_EVENT_PROGRESS:
|
|
|
|
TQApplication::postEvent (xineapp, new XineProgressEvent (((xine_progress_data_t *) event->data)->percent));
|
|
|
|
break;
|
|
|
|
case XINE_EVENT_MRL_REFERENCE:
|
|
|
|
fprintf(stderr, "XINE_EVENT_MRL_REFERENCE %s\n",
|
|
|
|
((xine_mrl_reference_data_ext_t*)event->data)->mrl);
|
|
|
|
TQApplication::postEvent (xineapp, new XineURLEvent (TQString::fromLocal8Bit (((xine_mrl_reference_data_ext_t*)event->data)->mrl)));
|
|
|
|
break;
|
|
|
|
case XINE_EVENT_FRAME_FORMAT_CHANGE:
|
|
|
|
fprintf (stderr, "XINE_EVENT_FRAME_FORMAT_CHANGE\n");
|
|
|
|
break;
|
|
|
|
case XINE_EVENT_UI_SET_TITLE:
|
|
|
|
{
|
|
|
|
xine_ui_data_t * data = (xine_ui_data_t *) event->data;
|
|
|
|
TQApplication::postEvent(xineapp, new XineTitleEvent(data->str));
|
|
|
|
fprintf (stderr, "Set title event %s\n", data->str);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XINE_EVENT_UI_CHANNELS_CHANGED: {
|
|
|
|
fprintf (stderr, "Channel changed event %d\n", firstframe);
|
|
|
|
mutex.lock ();
|
|
|
|
int w = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_WIDTH);
|
|
|
|
int h = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
|
|
|
|
int pos, l, nr;
|
|
|
|
xine_get_pos_length (stream, 0, &pos, &l);
|
|
|
|
char * langstr = new char [66];
|
|
|
|
alanglist.clear ();
|
|
|
|
slanglist.clear ();
|
|
|
|
|
|
|
|
nr =xine_get_stream_info(stream,XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
|
|
|
|
// if nrch > 25) nrch = 25
|
|
|
|
for (int i = 0; i < nr; ++i) {
|
|
|
|
if (!xine_get_audio_lang (stream, i, langstr))
|
|
|
|
continue;
|
|
|
|
TQString ls = TQString(TQString::fromLocal8Bit (langstr)).stripWhiteSpace();
|
|
|
|
if (ls.isEmpty ())
|
|
|
|
continue;
|
|
|
|
if (!slang.isEmpty () && alang == ls)
|
|
|
|
xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, i);
|
|
|
|
alanglist.push_back (ls);
|
|
|
|
fprintf (stderr, "alang %s\n", langstr);
|
|
|
|
}
|
|
|
|
nr = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
|
|
|
|
// if nrch > 25) nrch = 25
|
|
|
|
for (int i = 0; i < nr; ++i) {
|
|
|
|
if (!xine_get_spu_lang (stream, i, langstr))
|
|
|
|
continue;
|
|
|
|
TQString ls = TQString(TQString::fromLocal8Bit (langstr)).stripWhiteSpace();
|
|
|
|
if (ls.isEmpty ())
|
|
|
|
continue;
|
|
|
|
if (!slang.isEmpty () && slang == ls)
|
|
|
|
xine_set_param (stream, XINE_PARAM_SPU_CHANNEL, i);
|
|
|
|
slanglist.push_back (ls);
|
|
|
|
fprintf (stderr, "slang %s\n", langstr);
|
|
|
|
}
|
|
|
|
delete langstr;
|
|
|
|
mutex.unlock ();
|
|
|
|
movie_width = w;
|
|
|
|
movie_height = h;
|
|
|
|
movie_length = l;
|
|
|
|
TQApplication::postEvent (xineapp, new XineMovieParamEvent (l, w, h, alanglist, slanglist, firstframe));
|
|
|
|
if (running && firstframe)
|
|
|
|
firstframe = 0;
|
|
|
|
if (window_created && w > 0 && h > 0) {
|
|
|
|
XLockDisplay (display);
|
|
|
|
XResizeWindow (display, wid, movie_width, movie_height);
|
|
|
|
XFlush (display);
|
|
|
|
XUnlockDisplay (display);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XINE_EVENT_INPUT_MOUSE_MOVE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf (stderr, "event_listener %d\n", event->type);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // extern "C"
|
|
|
|
|
|
|
|
using namespace KMPlayer;
|
|
|
|
|
|
|
|
Backend::Backend ()
|
|
|
|
: DCOPObject (TQCString ("Backend")) {
|
|
|
|
}
|
|
|
|
|
|
|
|
Backend::~Backend () {}
|
|
|
|
|
|
|
|
void Backend::setURL (TQString url) {
|
|
|
|
mrl = url;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::setSubTitleURL (TQString url) {
|
|
|
|
sub_mrl = url;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::play (int repeat_count) {
|
|
|
|
xineapp->play (repeat_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::stop () {
|
|
|
|
TQTimer::singleShot (0, xineapp, TQT_SLOT (stop ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::pause () {
|
|
|
|
xineapp->pause ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::seek (int pos, bool /*absolute*/) {
|
|
|
|
xineapp->seek (pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::hue (int h, bool) {
|
|
|
|
xineapp->hue (65535 * (h + 100) / 200);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::saturation (int s, bool) {
|
|
|
|
xineapp->saturation (65535 * (s + 100) / 200);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::contrast (int c, bool) {
|
|
|
|
xineapp->contrast (65535 * (c + 100) / 200);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::brightness (int b, bool) {
|
|
|
|
xineapp->brightness (65535 * (b + 100) / 200);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::volume (int v, bool) {
|
|
|
|
xineapp->volume (v);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::frequency (int) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::setAudioLang (int id, TQString al) {
|
|
|
|
xineapp->setAudioLang (id, al);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::setSubtitle (int id, TQString sl) {
|
|
|
|
xineapp->setSubtitle (id, sl);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::quit () {
|
|
|
|
delete callback;
|
|
|
|
callback = 0L;
|
|
|
|
if (running)
|
|
|
|
stop ();
|
|
|
|
else
|
|
|
|
TQTimer::singleShot (0, tqApp, TQT_SLOT (quit ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool updateConfigEntry (const TQString & name, const TQString & value) {
|
|
|
|
fprintf (stderr, "%s=%s\n", name.ascii (), (const char *) value.local8Bit ());
|
|
|
|
bool changed = false;
|
|
|
|
xine_cfg_entry_t cfg_entry;
|
|
|
|
if (!xine_config_lookup_entry (xine, name.ascii (), &cfg_entry))
|
|
|
|
return false;
|
|
|
|
if (cfg_entry.type == XINE_CONFIG_TYPE_STRING ||
|
|
|
|
cfg_entry.type == XINE_CONFIG_TYPE_UNKNOWN) {
|
|
|
|
changed = strcmp (cfg_entry.str_value, value.ascii ());
|
|
|
|
cfg_entry.str_value = (char *) value.ascii ();
|
|
|
|
} else {
|
|
|
|
changed = cfg_entry.num_value != value.toInt ();
|
|
|
|
cfg_entry.num_value = value.toInt ();
|
|
|
|
}
|
|
|
|
xine_config_update_entry (xine, &cfg_entry);
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::setConfig (TQByteArray data) {
|
|
|
|
TQString err;
|
|
|
|
int line, column;
|
|
|
|
TQDomDocument dom;
|
|
|
|
if (dom.setContent (data, false, &err, &line, &column)) {
|
|
|
|
if (dom.childNodes().length() == 1) {
|
|
|
|
for (TQDomNode node = dom.firstChild().firstChild();
|
|
|
|
!node.isNull ();
|
|
|
|
node = node.nextSibling ()) {
|
|
|
|
TQDomNamedNodeMap attr = node.attributes ();
|
|
|
|
updateConfigEntry (attr.namedItem (attname).nodeValue (),
|
|
|
|
attr.namedItem (attvalue).nodeValue ());
|
|
|
|
}
|
|
|
|
xine_config_save (xine, configfile);
|
|
|
|
} else
|
|
|
|
err = TQString ("invalid data");
|
|
|
|
}
|
|
|
|
if (callback)
|
|
|
|
callback->errorMessage (0, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Backend::isPlaying () {
|
|
|
|
mutex.lock ();
|
|
|
|
bool b = running &&
|
|
|
|
(xine_get_status (stream) == XINE_STATUS_PLAY) &&
|
|
|
|
(xine_get_param (stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE);
|
|
|
|
mutex.unlock ();
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
KXinePlayer::KXinePlayer (int _argc, char ** _argv)
|
|
|
|
: TQApplication (_argc, _argv, false) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::init () {
|
|
|
|
xpos = 0;
|
|
|
|
ypos = 0;
|
|
|
|
width = 320;
|
|
|
|
height = 200;
|
|
|
|
|
|
|
|
XLockDisplay(display);
|
|
|
|
if (window_created)
|
|
|
|
wid = XCreateSimpleWindow(display, XDefaultRootWindow(display),
|
|
|
|
xpos, ypos, width, height, 1, 0, 0);
|
|
|
|
XSelectInput (display, wid,
|
|
|
|
(PointerMotionMask | ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask)); // | SubstructureNotifyMask));
|
|
|
|
XWindowAttributes attr;
|
|
|
|
XGetWindowAttributes(display, wid, &attr);
|
|
|
|
width = attr.width;
|
|
|
|
height = attr.height;
|
|
|
|
if (XShmQueryExtension(display) == True)
|
|
|
|
completion_event = XShmGetEventBase(display) + ShmCompletion;
|
|
|
|
else
|
|
|
|
completion_event = -1;
|
|
|
|
if (window_created) {
|
|
|
|
fprintf (stderr, "map %lu\n", wid);
|
|
|
|
XMapRaised(display, wid);
|
|
|
|
XSync(display, False);
|
|
|
|
}
|
|
|
|
//double d->res_h = 1.0 * DisplayWidth(display, screen) / DisplayWidthMM(display, screen);
|
|
|
|
//double d->res_v = 1.0 * DisplayHeight(display, screen) / DisplayHeightMM(display, screen);
|
|
|
|
XUnlockDisplay(display);
|
|
|
|
vis.display = display;
|
|
|
|
vis.screen = screen;
|
|
|
|
vis.d = wid;
|
|
|
|
vis.dest_size_cb = dest_size_cb;
|
|
|
|
vis.frame_output_cb = frame_output_cb;
|
|
|
|
vis.user_data = NULL;
|
|
|
|
//pixel_aspect = d->res_v / d->res_h;
|
|
|
|
|
|
|
|
//if(fabs(pixel_aspect - 1.0) < 0.01)
|
|
|
|
pixel_aspect = 1.0;
|
|
|
|
|
|
|
|
const char *const * pp = xine_list_post_plugins_typed (xine, XINE_POST_TYPE_AUDIO_VISUALIZATION);
|
|
|
|
int i;
|
|
|
|
for (i = 0; pp[i]; i++);
|
|
|
|
const char ** options = new const char * [i+2];
|
|
|
|
options[0] = "none";
|
|
|
|
for (i = 0; pp[i]; i++)
|
|
|
|
options[i+1] = pp[i];
|
|
|
|
options[i+1] = 0L;
|
|
|
|
xine_config_register_enum (xine, "audio.visualization", 0, (char ** ) options, 0L, 0L, 0, xine_config_cb, 0L);
|
|
|
|
if (!callback)
|
|
|
|
TQTimer::singleShot (10, this, TQT_SLOT (play ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
KXinePlayer::~KXinePlayer () {
|
|
|
|
if (window_created) {
|
|
|
|
XLockDisplay (display);
|
|
|
|
fprintf (stderr, "unmap %lu\n", wid);
|
|
|
|
XUnmapWindow (display, wid);
|
|
|
|
XDestroyWindow(display, wid);
|
|
|
|
XSync (display, False);
|
|
|
|
XUnlockDisplay (display);
|
|
|
|
}
|
|
|
|
xineapp = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
void getConfigEntries (TQByteArray & buf) {
|
|
|
|
xine_cfg_entry_t entry;
|
|
|
|
TQDomDocument doc;
|
|
|
|
TQDomElement root = doc.createElement (TQString ("document"));
|
|
|
|
for (int i = xine_config_get_first_entry (xine, &entry);
|
|
|
|
i;
|
|
|
|
i = xine_config_get_next_entry (xine, &entry)) {
|
|
|
|
TQDomElement elm = doc.createElement (elmentry);
|
|
|
|
elm.setAttribute (attname, TQString (entry.key));
|
|
|
|
if (entry.type == XINE_CONFIG_TYPE_STRING || entry.type == XINE_CONFIG_TYPE_UNKNOWN) {
|
|
|
|
elm.setAttribute (atttype, valstring);
|
|
|
|
elm.setAttribute (attvalue, TQString (entry.str_value));
|
|
|
|
} else {
|
|
|
|
elm.setAttribute (attdefault, TQString::number (entry.num_default));
|
|
|
|
elm.setAttribute (attvalue, TQString::number (entry.num_value));
|
|
|
|
switch (entry.type) {
|
|
|
|
case XINE_CONFIG_TYPE_RANGE:
|
|
|
|
elm.setAttribute (atttype, valrange);
|
|
|
|
elm.setAttribute (attstart, TQString::number (entry.range_min));
|
|
|
|
elm.setAttribute (attend, TQString::number (entry.range_max));
|
|
|
|
break;
|
|
|
|
case XINE_CONFIG_TYPE_ENUM:
|
|
|
|
elm.setAttribute (atttype, valenum);
|
|
|
|
for (int i = 0; entry.enum_values[i]; i++) {
|
|
|
|
TQDomElement item = doc.createElement (elmitem);
|
|
|
|
item.setAttribute (attvalue, TQString (entry.enum_values[i]));
|
|
|
|
elm.appendChild (item);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XINE_CONFIG_TYPE_NUM:
|
|
|
|
elm.setAttribute (atttype, valnum);
|
|
|
|
break;
|
|
|
|
case XINE_CONFIG_TYPE_BOOL:
|
|
|
|
elm.setAttribute (atttype, valbool);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf (stderr, "unhandled config type: %d\n", entry.type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (entry.help)
|
|
|
|
elm.appendChild (doc.createTextNode (TQString::fromUtf8 (entry.help)));
|
|
|
|
root.appendChild (elm);
|
|
|
|
}
|
|
|
|
doc.appendChild (root);
|
|
|
|
TQString exp = doc.toString ();
|
|
|
|
TQCString cexp = exp.utf8 ();
|
|
|
|
buf.duplicate (cexp);
|
|
|
|
buf.resize (cexp.length ()); // strip terminating \0
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::play (int repeat) {
|
|
|
|
fprintf (stderr, "play mrl: '%s'\n", (const char *) mrl.local8Bit ());
|
|
|
|
mutex.lock ();
|
|
|
|
repeat_count = repeat;
|
|
|
|
if (running) {
|
|
|
|
if (xine_get_status (stream) == XINE_STATUS_PLAY &&
|
|
|
|
xine_get_param (stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE)
|
|
|
|
xine_set_param( stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
|
|
|
|
mutex.unlock ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
movie_pos = 0;
|
|
|
|
movie_width = 0;
|
|
|
|
movie_height = 0;
|
|
|
|
|
|
|
|
if (mrl.startsWith ("cdda://"))
|
|
|
|
mrl = TQString ("cdda:/") + mrl.mid (7);
|
|
|
|
stream = xine_stream_new (xine, ao_port, vo_port);
|
|
|
|
event_queue = xine_event_new_queue (stream);
|
|
|
|
xine_event_create_listener_thread (event_queue, event_listener, NULL);
|
|
|
|
if (mrl == "cdda:/") {
|
|
|
|
int nr;
|
|
|
|
char ** mrls = xine_get_autoplay_mrls (xine, "CD", &nr);
|
|
|
|
running = 1;
|
|
|
|
for (int i = 0; i < nr; i++) {
|
|
|
|
TQString m (mrls[i]);
|
|
|
|
TQString title;
|
|
|
|
if (xine_open (stream, mrls[i])) {
|
|
|
|
const char * t = xine_get_meta_info (stream, XINE_META_INFO_TITLE);
|
|
|
|
if (t && t[0])
|
|
|
|
title = TQString::fromUtf8 (t);
|
|
|
|
xine_close (stream);
|
|
|
|
}
|
|
|
|
if (callback)
|
|
|
|
callback->subMrl (m, title);
|
|
|
|
else
|
|
|
|
printf ("track %s\n", m.utf8 ().data ());
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
finished ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xine_port_send_gui_data(vo_port, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
|
|
|
|
|
|
|
|
running = 1;
|
|
|
|
TQString mrlsetup = mrl;
|
|
|
|
if (!rec_mrl.isEmpty ()) {
|
|
|
|
char * rm = strdup (rec_mrl.local8Bit ());
|
|
|
|
char *bn = basename (rm);
|
|
|
|
char *dn = dirname (rm);
|
|
|
|
if (bn)
|
|
|
|
updateConfigEntry (TQString ("media.capture.save_dir"), TQString::fromLocal8Bit (dn));
|
|
|
|
mrlsetup += TQString ("#save:") + TQString::fromLocal8Bit (bn);
|
|
|
|
free (rm);
|
|
|
|
}
|
|
|
|
if (!xine_open (stream, (const char *) mrlsetup.local8Bit ())) {
|
|
|
|
fprintf(stderr, "Unable to open mrl '%s'\n", (const char *) mrl.local8Bit ());
|
|
|
|
mutex.unlock ();
|
|
|
|
finished ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_SATURATION, movie_saturation);
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_BRIGHTNESS, movie_brightness);
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_CONTRAST, movie_contrast);
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_HUE, movie_hue);
|
|
|
|
|
|
|
|
if (!sub_mrl.isEmpty ()) {
|
|
|
|
fprintf(stderr, "Using subtitles from '%s'\n", (const char *) sub_mrl.local8Bit ());
|
|
|
|
sub_stream = xine_stream_new (xine, NULL, vo_port);
|
|
|
|
if (xine_open (sub_stream, (const char *) sub_mrl.local8Bit ())) {
|
|
|
|
xine_stream_master_slave (stream, sub_stream,
|
|
|
|
XINE_MASTER_SLAVE_PLAY | XINE_MASTER_SLAVE_STOP);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Unable to open subtitles from '%s'\n", (const char *) sub_mrl.local8Bit ());
|
|
|
|
xine_dispose (sub_stream);
|
|
|
|
sub_stream = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!xine_play (stream, 0, 0)) {
|
|
|
|
fprintf(stderr, "Unable to play mrl '%s'\n", (const char *) mrl.local8Bit ());
|
|
|
|
mutex.unlock ();
|
|
|
|
finished ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
audio_vis = false;
|
|
|
|
if (xine_get_stream_info (stream, XINE_STREAM_INFO_HAS_VIDEO))
|
|
|
|
TQApplication::postEvent(xineapp, new TQEvent((TQEvent::Type)event_video));
|
|
|
|
else
|
|
|
|
audio_vis = xine_config_lookup_entry
|
|
|
|
(xine, "audio.visualization", &audio_vis_cfg_entry);
|
|
|
|
mutex.unlock ();
|
|
|
|
if (audio_vis)
|
|
|
|
xine_config_cb (0L, &audio_vis_cfg_entry);
|
|
|
|
if (callback)
|
|
|
|
firstframe = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::stop () {
|
|
|
|
if (!running) return;
|
|
|
|
fprintf(stderr, "stop\n");
|
|
|
|
mutex.lock ();
|
|
|
|
repeat_count = 0;
|
|
|
|
if (sub_stream)
|
|
|
|
xine_stop (sub_stream);
|
|
|
|
xine_stop (stream);
|
|
|
|
mutex.unlock ();
|
|
|
|
TQTimer::singleShot (10, this, TQT_SLOT (postFinished ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::postFinished () {
|
|
|
|
TQApplication::postEvent (xineapp, new TQEvent ((TQEvent::Type) event_finished));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::pause () {
|
|
|
|
if (!running) return;
|
|
|
|
mutex.lock ();
|
|
|
|
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
|
|
|
|
xine_set_param (stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::finished () {
|
|
|
|
TQTimer::singleShot (10, this, TQT_SLOT (stop ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::setAudioLang (int id, const TQString & al) {
|
|
|
|
alang = al;
|
|
|
|
mutex.lock ();
|
|
|
|
if (xine_get_status (stream) == XINE_STATUS_PLAY)
|
|
|
|
xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, id);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::setSubtitle (int id, const TQString & sl) {
|
|
|
|
slang = sl;
|
|
|
|
mutex.lock ();
|
|
|
|
if (xine_get_status (stream) == XINE_STATUS_PLAY)
|
|
|
|
xine_set_param (stream, XINE_PARAM_SPU_CHANNEL, id);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::updatePosition () {
|
|
|
|
if (!running || !callback) return;
|
|
|
|
int pos;
|
|
|
|
mutex.lock ();
|
|
|
|
xine_get_pos_length (stream, 0, &pos, &movie_length);
|
|
|
|
mutex.unlock ();
|
|
|
|
if (movie_pos != pos) {
|
|
|
|
movie_pos = pos;
|
|
|
|
callback->moviePosition (pos/100);
|
|
|
|
}
|
|
|
|
TQTimer::singleShot (500, this, TQT_SLOT (updatePosition ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::saturation (int val) {
|
|
|
|
movie_saturation = val;
|
|
|
|
if (running) {
|
|
|
|
mutex.lock ();
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_SATURATION, val);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::hue (int val) {
|
|
|
|
movie_hue = val;
|
|
|
|
if (running) {
|
|
|
|
mutex.lock ();
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_HUE, val);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::contrast (int val) {
|
|
|
|
movie_contrast = val;
|
|
|
|
if (running) {
|
|
|
|
mutex.lock ();
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_CONTRAST, val);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::brightness (int val) {
|
|
|
|
movie_brightness = val;
|
|
|
|
if (running) {
|
|
|
|
mutex.lock ();
|
|
|
|
xine_set_param (stream, XINE_PARAM_VO_BRIGHTNESS, val);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::volume (int val) {
|
|
|
|
movie_volume = val;
|
|
|
|
if (running) {
|
|
|
|
mutex.lock ();
|
|
|
|
xine_set_param( stream, XINE_PARAM_AUDIO_VOLUME, val);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::seek (int val) {
|
|
|
|
if (running) {
|
|
|
|
fprintf(stderr, "seek %d\n", val);
|
|
|
|
mutex.lock ();
|
|
|
|
if (!xine_play (stream, 0, val * 100)) {
|
|
|
|
fprintf(stderr, "Unable to seek to %d :-(\n", val);
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KXinePlayer::event (TQEvent * e) {
|
|
|
|
switch (e->type()) {
|
|
|
|
case event_finished: {
|
|
|
|
fprintf (stderr, "event_finished\n");
|
|
|
|
if (audio_vis) {
|
|
|
|
audio_vis_cfg_entry.num_value = 0;
|
|
|
|
xine_config_cb (0L, &audio_vis_cfg_entry);
|
|
|
|
}
|
|
|
|
mutex.lock ();
|
|
|
|
running = 0;
|
|
|
|
firstframe = 0;
|
|
|
|
if (sub_stream) {
|
|
|
|
xine_dispose (sub_stream);
|
|
|
|
sub_stream = 0L;
|
|
|
|
}
|
|
|
|
if (stream) {
|
|
|
|
xine_event_dispose_queue (event_queue);
|
|
|
|
xine_dispose (stream);
|
|
|
|
stream = 0L;
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
//XLockDisplay (display);
|
|
|
|
//XClearWindow (display, wid);
|
|
|
|
//XUnlockDisplay (display);
|
|
|
|
if (callback)
|
|
|
|
callback->finished ();
|
|
|
|
else
|
|
|
|
TQTimer::singleShot (0, this, TQT_SLOT (quit ()));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case event_size: {
|
|
|
|
if (callback) {
|
|
|
|
XineMovieParamEvent * se = static_cast <XineMovieParamEvent *> (e);
|
|
|
|
if (se->length < 0) se->length = 0;
|
|
|
|
callback->movieParams (se->length/100, se->width, se->height, se->height ? 1.0*se->width/se->height : 1.0, se->alang, se->slang);
|
|
|
|
if (se->first_frame) {
|
|
|
|
callback->playing ();
|
|
|
|
TQTimer::singleShot (500, this, TQT_SLOT (updatePosition ()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case event_progress: {
|
|
|
|
XineProgressEvent * pe = static_cast <XineProgressEvent *> (e);
|
|
|
|
if (callback)
|
|
|
|
callback->loadingProgress (pe->progress);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case event_url: {
|
|
|
|
XineURLEvent * ue = static_cast <XineURLEvent *> (e);
|
|
|
|
if (callback)
|
|
|
|
callback->subMrl (ue->url, TQString ());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case event_title: {
|
|
|
|
XineTitleEvent * ue = static_cast <XineTitleEvent *> (e);
|
|
|
|
if (callback)
|
|
|
|
callback->statusMessage ((int) KMPlayer::Callback::stat_newtitle, ue->title);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case event_video:
|
|
|
|
if (callback)
|
|
|
|
callback->statusMessage ((int) KMPlayer::Callback::stat_hasvideo, TQString ());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXinePlayer::saveState (TQSessionManager & sm) {
|
|
|
|
if (callback)
|
|
|
|
sm.setRestartHint (TQSessionManager::RestartNever);
|
|
|
|
}
|
|
|
|
|
|
|
|
XineMovieParamEvent::XineMovieParamEvent(int l, int w, int h, const TQStringList & a, const TQStringList & s, bool ff)
|
|
|
|
: TQEvent ((TQEvent::Type) event_size),
|
|
|
|
length (l), width (w), height (h), alang (a), slang (s) , first_frame (ff)
|
|
|
|
{}
|
|
|
|
|
|
|
|
XineURLEvent::XineURLEvent (const TQString & u)
|
|
|
|
: TQEvent ((TQEvent::Type) event_url), url (u)
|
|
|
|
{}
|
|
|
|
|
|
|
|
XineTitleEvent::XineTitleEvent (const char * t)
|
|
|
|
: TQEvent ((TQEvent::Type) event_title), title (TQString::fromUtf8 (t))
|
|
|
|
{
|
|
|
|
TQUrl::decode (title);
|
|
|
|
}
|
|
|
|
|
|
|
|
XineProgressEvent::XineProgressEvent (const int p)
|
|
|
|
: TQEvent ((TQEvent::Type) event_progress), progress (p)
|
|
|
|
{}
|
|
|
|
|
|
|
|
//static bool translateCoordinates (int wx, int wy, int mx, int my) {
|
|
|
|
// movie_width
|
|
|
|
class XEventThread : public TQThread {
|
|
|
|
protected:
|
|
|
|
void run () {
|
|
|
|
Time prev_click_time = 0;
|
|
|
|
int prev_click_x = 0;
|
|
|
|
int prev_click_y = 0;
|
|
|
|
while (true) {
|
|
|
|
XEvent xevent;
|
|
|
|
XNextEvent(display, &xevent);
|
|
|
|
switch(xevent.type) {
|
|
|
|
case ClientMessage:
|
|
|
|
if (xevent.xclient.message_type == quit_atom) {
|
|
|
|
fprintf(stderr, "request quit\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KeyPress:
|
|
|
|
{
|
|
|
|
XKeyEvent kevent;
|
|
|
|
KeySym ksym;
|
|
|
|
char kbuf[256];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
kevent = xevent.xkey;
|
|
|
|
|
|
|
|
XLockDisplay(display);
|
|
|
|
len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL);
|
|
|
|
XUnlockDisplay(display);
|
|
|
|
fprintf(stderr, "keypressed 0x%x 0x%x\n", kevent.keycode, ksym);
|
|
|
|
|
|
|
|
switch (ksym) {
|
|
|
|
|
|
|
|
case XK_q:
|
|
|
|
case XK_Q:
|
|
|
|
xineapp->lock ();
|
|
|
|
xineapp->stop ();
|
|
|
|
xineapp->unlock ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_p: // previous
|
|
|
|
mutex.lock ();
|
|
|
|
if (stream) {
|
|
|
|
xine_event_t xine_event = {
|
|
|
|
XINE_EVENT_INPUT_PREVIOUS,
|
|
|
|
stream, 0L, 0, { 0, 0 }
|
|
|
|
};
|
|
|
|
xine_event_send (stream, &xine_event);
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_n: // next
|
|
|
|
mutex.lock ();
|
|
|
|
if (stream) {
|
|
|
|
xine_event_t xine_event = {
|
|
|
|
XINE_EVENT_INPUT_NEXT,
|
|
|
|
stream, 0L, 0, { 0, 0 }
|
|
|
|
};
|
|
|
|
xine_event_send (stream, &xine_event);
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_u: // up menu
|
|
|
|
mutex.lock ();
|
|
|
|
if (stream) {
|
|
|
|
xine_event_t xine_event = {
|
|
|
|
XINE_EVENT_INPUT_MENU1,
|
|
|
|
stream, 0L, 0, { 0, 0 }
|
|
|
|
};
|
|
|
|
xine_event_send (stream, &xine_event);
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_r: // root menu
|
|
|
|
mutex.lock ();
|
|
|
|
if (stream) {
|
|
|
|
xine_event_t xine_event = {
|
|
|
|
XINE_EVENT_INPUT_MENU3,
|
|
|
|
stream, 0L, 0, { 0, 0 }
|
|
|
|
};
|
|
|
|
xine_event_send (stream, &xine_event);
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Up:
|
|
|
|
xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
|
|
|
|
(xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Down:
|
|
|
|
xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
|
|
|
|
(xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_plus:
|
|
|
|
xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
|
|
|
|
(xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_minus:
|
|
|
|
xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
|
|
|
|
(xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_space:
|
|
|
|
if(xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE)
|
|
|
|
xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
|
|
|
|
else
|
|
|
|
xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Expose:
|
|
|
|
if(xevent.xexpose.count != 0 || !stream || xevent.xexpose.window != wid)
|
|
|
|
break;
|
|
|
|
mutex.lock ();
|
|
|
|
xine_port_send_gui_data(vo_port, XINE_GUI_SEND_EXPOSE_EVENT, &xevent);
|
|
|
|
mutex.unlock ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ConfigureNotify:
|
|
|
|
{
|
|
|
|
Window tmp_win;
|
|
|
|
|
|
|
|
width = xevent.xconfigure.width;
|
|
|
|
height = xevent.xconfigure.height;
|
|
|
|
if((xevent.xconfigure.x == 0) && (xevent.xconfigure.y == 0)) {
|
|
|
|
XLockDisplay(display);
|
|
|
|
XTranslateCoordinates(display, xevent.xconfigure.window,
|
|
|
|
DefaultRootWindow(xevent.xconfigure.display),
|
|
|
|
0, 0, &xpos, &ypos, &tmp_win);
|
|
|
|
XUnlockDisplay(display);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xpos = xevent.xconfigure.x;
|
|
|
|
ypos = xevent.xconfigure.y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case MotionNotify:
|
|
|
|
if (stream) {
|
|
|
|
XMotionEvent *mev = (XMotionEvent *) &xevent;
|
|
|
|
x11_rectangle_t rect = { mev->x, mev->y, 0, 0 };
|
|
|
|
if (xine_port_send_gui_data(vo_port, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*) &rect) == -1)
|
|
|
|
break;
|
|
|
|
xine_input_data_t data;
|
|
|
|
data.x = rect.x;
|
|
|
|
data.y = rect.y;
|
|
|
|
data.button = 0;
|
|
|
|
xine_event_t xine_event = {
|
|
|
|
XINE_EVENT_INPUT_MOUSE_MOVE,
|
|
|
|
stream, &data, sizeof (xine_input_data_t),
|
|
|
|
{ 0 , 0 }
|
|
|
|
};
|
|
|
|
mutex.lock ();
|
|
|
|
xine_event_send (stream, &xine_event);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ButtonPress: {
|
|
|
|
XButtonEvent *bev = (XButtonEvent *) &xevent;
|
|
|
|
int dx = prev_click_x - bev->x;
|
|
|
|
int dy = prev_click_y - bev->y;
|
|
|
|
if (bev->time - prev_click_time < 400 &&
|
|
|
|
(dx * dx + dy * dy) < 25) {
|
|
|
|
xineapp->lock ();
|
|
|
|
if (callback)
|
|
|
|
callback->toggleFullScreen ();
|
|
|
|
xineapp->unlock ();
|
|
|
|
}
|
|
|
|
prev_click_time = bev->time;
|
|
|
|
prev_click_x = bev->x;
|
|
|
|
prev_click_y = bev->y;
|
|
|
|
if (stream) {
|
|
|
|
fprintf(stderr, "ButtonPress\n");
|
|
|
|
XButtonEvent *bev = (XButtonEvent *) &xevent;
|
|
|
|
x11_rectangle_t rect = { bev->x, bev->y, 0, 0 };
|
|
|
|
if (xine_port_send_gui_data(vo_port, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*) &rect) == -1)
|
|
|
|
break;
|
|
|
|
xine_input_data_t data;
|
|
|
|
data.x = rect.x;
|
|
|
|
data.y = rect.y;
|
|
|
|
data.button = 1;
|
|
|
|
xine_event_t xine_event = {
|
|
|
|
XINE_EVENT_INPUT_MOUSE_BUTTON,
|
|
|
|
stream, &data, sizeof (xine_input_data_t),
|
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
mutex.lock ();
|
|
|
|
xine_event_send (stream, &xine_event);
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NoExpose:
|
|
|
|
//fprintf (stderr, "NoExpose %lu\n", xevent.xnoexpose.drawable);
|
|
|
|
break;
|
|
|
|
case CreateNotify:
|
|
|
|
fprintf (stderr, "CreateNotify: %lu %lu %d,%d %dx%d\n",
|
|
|
|
xevent.xcreatewindow.window, xevent.xcreatewindow.parent,
|
|
|
|
xevent.xcreatewindow.x, xevent.xcreatewindow.y,
|
|
|
|
xevent.xcreatewindow.width, xevent.xcreatewindow.height);
|
|
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
|
|
fprintf (stderr, "DestroyNotify: %lu\n", xevent.xdestroywindow.window);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (xevent.type < LASTEvent)
|
|
|
|
fprintf (stderr, "event %d\n", xevent.type);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(xevent.type == completion_event && stream)
|
|
|
|
xine_port_send_gui_data(vo_port, XINE_GUI_SEND_COMPLETION_EVENT, &xevent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
const char *dvd_device = 0L;
|
|
|
|
const char *vcd_device = 0L;
|
|
|
|
const char *grab_device = 0L;
|
|
|
|
if (!XInitThreads ()) {
|
|
|
|
fprintf (stderr, "XInitThreads () failed\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
display = XOpenDisplay(NULL);
|
|
|
|
screen = XDefaultScreen(display);
|
|
|
|
quit_atom = XInternAtom (display, "kxineplayer_quit", false);
|
|
|
|
|
|
|
|
snprintf(configfile, sizeof (configfile), "%s%s", xine_get_homedir(), "/.xine/config2");
|
|
|
|
xineapp = new KXinePlayer (argc, argv);
|
|
|
|
window_created = true;
|
|
|
|
TQString vo_driver ("auto");
|
|
|
|
TQString ao_driver ("auto");
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
if (!strcmp (argv [i], "-vo") && ++i < argc) {
|
|
|
|
vo_driver = argv [i];
|
|
|
|
} else if (!strcmp (argv [i], "-ao") && ++i < argc) {
|
|
|
|
ao_driver = argv [i];
|
|
|
|
} else if (!strcmp (argv [i], "-dvd-device") && ++i < argc) {
|
|
|
|
dvd_device = argv [i];
|
|
|
|
} else if (!strcmp (argv [i], "-vcd-device") && ++i < argc) {
|
|
|
|
vcd_device = argv [i];
|
|
|
|
} else if (!strcmp (argv [i], "-vd") && ++i < argc) {
|
|
|
|
grab_device = argv [i];
|
|
|
|
} else if ((!strcmp (argv [i], "-wid") ||
|
|
|
|
!strcmp (argv [i], "-window-id")) && ++i < argc) {
|
|
|
|
wid = atol (argv [i]);
|
|
|
|
window_created = false;
|
|
|
|
} else if (!strcmp (argv [i], "-root")) {
|
|
|
|
wid = XDefaultRootWindow (display);
|
|
|
|
window_created = false;
|
|
|
|
} else if (!strcmp (argv [i], "-window")) {
|
|
|
|
;
|
|
|
|
} else if (!strcmp (argv [i], "-sub") && ++i < argc) {
|
|
|
|
sub_mrl = TQString (argv [i]);
|
|
|
|
} else if (!strcmp (argv [i], "-lang") && ++i < argc) {
|
|
|
|
slang = alang = TQString (argv [i]);
|
|
|
|
} else if (!strcmp (argv [i], "-v")) {
|
|
|
|
xine_verbose = true;
|
|
|
|
} else if (!strcmp (argv [i], "-vv")) {
|
|
|
|
xine_verbose = xine_vverbose = true;
|
|
|
|
} else if (!strcmp (argv [i], "-c")) {
|
|
|
|
wants_config = true;
|
|
|
|
} else if (!strcmp (argv [i], "-f") && ++i < argc) {
|
|
|
|
strncpy (configfile, argv [i], sizeof (configfile));
|
|
|
|
configfile[sizeof (configfile) - 1] = 0;
|
|
|
|
} else if (!strcmp (argv [i], "-cb") && ++i < argc) {
|
|
|
|
TQString str = argv [i];
|
|
|
|
int pos = str.find ('/');
|
|
|
|
if (pos > -1) {
|
|
|
|
fprintf (stderr, "callback is %s %s\n", str.left (pos).ascii (), str.mid (pos + 1).ascii ());
|
|
|
|
callback = new KMPlayer::Callback_stub
|
|
|
|
(str.left (pos).ascii (), str.mid (pos + 1).ascii ());
|
|
|
|
}
|
|
|
|
} else if (!strcmp (argv [i], "-rec") && i < argc - 1) {
|
|
|
|
rec_mrl = TQString::fromLocal8Bit (argv [++i]);
|
|
|
|
} else if (!strcmp (argv [i], "-loop") && i < argc - 1) {
|
|
|
|
repeat_count = atol (argv [++i]);
|
|
|
|
} else {
|
|
|
|
if (mrl.startsWith ("-session")) {
|
|
|
|
delete xineapp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
mrl = TQString::fromLocal8Bit (argv [i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool config_changed = !TQFile (configfile).exists ();
|
|
|
|
|
|
|
|
if (!callback && mrl.isEmpty ()) {
|
|
|
|
fprintf (stderr, "usage: %s [-vo (xv|xshm)] [-ao (arts|esd|..)] "
|
|
|
|
"[-f <xine config file>] [-dvd-device <device>] "
|
|
|
|
"[-vcd-device <device>] [-vd <video device>] "
|
|
|
|
"[-wid <X11 Window>|-window-id <X11 Window>|-root] "
|
|
|
|
"[-sub <subtitle url>] [-lang <lang>] [(-v|-vv)] "
|
|
|
|
"[-cb <DCOP callback name> [-c]] "
|
|
|
|
"[-loop <repeat>] [<url>]\n", argv[0]);
|
|
|
|
delete xineapp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
XEventThread * eventThread = new XEventThread;
|
|
|
|
eventThread->start ();
|
|
|
|
|
|
|
|
DCOPClient dcopclient;
|
|
|
|
dcopclient.registerAs ("kxineplayer");
|
|
|
|
Backend player;
|
|
|
|
|
|
|
|
xine = xine_new();
|
|
|
|
if (xine_verbose)
|
|
|
|
xine_engine_set_param (xine, XINE_ENGINE_PARAM_VERBOSITY, xine_vverbose ? XINE_VERBOSITY_DEBUG : XINE_VERBOSITY_LOG);
|
|
|
|
xine_config_load(xine, configfile);
|
|
|
|
xine_init(xine);
|
|
|
|
|
|
|
|
xineapp->init ();
|
|
|
|
|
|
|
|
if (dvd_device)
|
|
|
|
config_changed |= updateConfigEntry (TQString ("input.dvd_device"), TQString (dvd_device));
|
|
|
|
if (vcd_device)
|
|
|
|
config_changed |= updateConfigEntry (TQString ("input.vcd_device"), TQString (vcd_device));
|
|
|
|
if (grab_device)
|
|
|
|
config_changed |= updateConfigEntry (TQString ("media.video4linux.video_device"), TQString (grab_device));
|
|
|
|
|
|
|
|
if (config_changed)
|
|
|
|
xine_config_save (xine, configfile);
|
|
|
|
|
|
|
|
TQStringList vos = TQStringList::split (',', vo_driver);
|
|
|
|
for (int i = 0; i < vos.size (); i++) {
|
|
|
|
if (vos[i] == "x11")
|
|
|
|
vos[i] = "xshm";
|
|
|
|
else if (vos[i] == "gl")
|
|
|
|
vos[i] = "opengl";
|
|
|
|
fprintf (stderr, "trying video driver %s ..\n", vos[i].ascii ());
|
|
|
|
vo_port = xine_open_video_driver(xine, vos[i].ascii (),
|
|
|
|
XINE_VISUAL_TYPE_X11, (void *) &vis);
|
|
|
|
if (vo_port)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!vo_port)
|
|
|
|
fprintf (stderr, "no video driver found\n");
|
|
|
|
TQStringList aos = TQStringList::split (',', ao_driver);
|
|
|
|
for (int i = 0; i < aos.size (); i++) {
|
|
|
|
fprintf (stderr, "trying audio driver %s ..\n", aos[i].ascii ());
|
|
|
|
ao_port = xine_open_audio_driver (xine, aos[i].ascii (), NULL);
|
|
|
|
if (ao_port)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!ao_port)
|
|
|
|
fprintf (stderr, "audio driver initialisation failed\n");
|
|
|
|
stream = xine_stream_new (xine, ao_port, vo_port);
|
|
|
|
|
|
|
|
TQByteArray buf;
|
|
|
|
if (wants_config) {
|
|
|
|
/* TODO? Opening the output drivers in front, will add more config
|
|
|
|
settings. Unfortunately, that also adds a second in startup..
|
|
|
|
const char *const * aops = xine_list_audio_output_plugins (xine);
|
|
|
|
for (const char *const* aop = aops; *aop; aop++) {
|
|
|
|
xine_audio_port_t * ap = xine_open_audio_driver (xine, *aop, 0L);
|
|
|
|
xine_close_audio_driver (xine, ap);
|
|
|
|
fprintf (stderr, "audio output: %s\n", *aop);
|
|
|
|
}
|
|
|
|
const char *const * vops = xine_list_video_output_plugins (xine);
|
|
|
|
for (const char *const* vop = vops; *vop; vop++) {
|
|
|
|
xine_video_port_t * vp = xine_open_video_driver (xine, *vop, XINE_VISUAL_TYPE_NONE, 0L);
|
|
|
|
xine_close_video_driver (xine, vp);
|
|
|
|
fprintf (stderr, "vidio output: %s\n", *vop);
|
|
|
|
}*/
|
|
|
|
getConfigEntries (buf);
|
|
|
|
}
|
|
|
|
if (callback)
|
|
|
|
callback->started (dcopclient.appId (), buf);
|
|
|
|
else
|
|
|
|
;//printf ("%s\n", TQString (buf).ascii ());
|
|
|
|
xineapp->exec ();
|
|
|
|
|
|
|
|
if (sub_stream)
|
|
|
|
xine_dispose (sub_stream);
|
|
|
|
if (stream) {
|
|
|
|
xine_event_dispose_queue (event_queue);
|
|
|
|
xine_dispose (stream);
|
|
|
|
}
|
|
|
|
if (ao_port)
|
|
|
|
xine_close_audio_driver (xine, ao_port);
|
|
|
|
if (vo_port)
|
|
|
|
xine_close_video_driver (xine, vo_port);
|
|
|
|
XLockDisplay(display);
|
|
|
|
XEvent ev;
|
|
|
|
ev.xclient.type = ClientMessage;
|
|
|
|
ev.xclient.serial = 0;
|
|
|
|
ev.xclient.send_event = true;
|
|
|
|
ev.xclient.display = display;
|
|
|
|
ev.xclient.window = wid;
|
|
|
|
ev.xclient.message_type = quit_atom;
|
|
|
|
ev.xclient.format = 8;
|
|
|
|
ev.xclient.data.b[0] = 0;
|
|
|
|
XSendEvent (display, wid, false, StructureNotifyMask, &ev);
|
|
|
|
XFlush (display);
|
|
|
|
XUnlockDisplay(display);
|
|
|
|
eventThread->wait (500);
|
|
|
|
delete eventThread;
|
|
|
|
|
|
|
|
xineapp->stop ();
|
|
|
|
delete xineapp;
|
|
|
|
|
|
|
|
xine_exit (xine);
|
|
|
|
|
|
|
|
fprintf (stderr, "closing display\n");
|
|
|
|
XCloseDisplay (display);
|
|
|
|
fprintf (stderr, "done\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "xineplayer.moc"
|