diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-17 00:54:13 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-17 00:54:13 +0000 |
commit | 092be7678b67552cb3161fe162242bf8d3aeed2f (patch) | |
tree | be0693f45b101252c370e40f6e84da2cd7a52f75 /src/xineplayer.cpp | |
download | kmplayer-092be7678b67552cb3161fe162242bf8d3aeed2f.tar.gz kmplayer-092be7678b67552cb3161fe162242bf8d3aeed2f.zip |
Added old abandoned KDE3 version of kmplayer
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kmplayer@1091557 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/xineplayer.cpp')
-rw-r--r-- | src/xineplayer.cpp | 1239 |
1 files changed, 1239 insertions, 0 deletions
diff --git a/src/xineplayer.cpp b/src/xineplayer.cpp new file mode 100644 index 0000000..17e6fd2 --- /dev/null +++ b/src/xineplayer.cpp @@ -0,0 +1,1239 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2003 Koos Vriezen <[email protected]> + + 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 <qcstring.h> +#include <qtimer.h> +#include <qfile.h> +#include <qurl.h> +#include <qthread.h> +#include <qmutex.h> +#include <qdom.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 QMutex 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 = QEvent::User; +static const int event_progress = QEvent::User + 2; +static const int event_url = QEvent::User + 3; +static const int event_size = QEvent::User + 4; +static const int event_title = QEvent::User + 5; +static const int event_video = QEvent::User + 6; +static QString mrl; +static QString sub_mrl; +static QString rec_mrl; +static QString alang, slang; +static QStringList alanglist, slanglist; + +static QString elmentry ("entry"); +static QString elmitem ("item"); +static QString attname ("name"); +static QString atttype ("type"); +static QString attdefault ("DEFAULT"); +static QString attvalue ("value"); +static QString attstart ("START"); +static QString attend ("end"); +static QString valrange ("range"); +static QString valnum ("num"); +static QString valbool ("bool"); +static QString valenum ("enum"); +static QString 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 (); + QApplication::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 + QApplication::postEvent (xineapp, new QEvent ((QEvent::Type) event_finished)); + break; + case XINE_EVENT_PROGRESS: + QApplication::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_t*)event->data)->mrl); + QApplication::postEvent (xineapp, new XineURLEvent (QString::fromLocal8Bit (((xine_mrl_reference_data_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; + QApplication::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; + QString ls = QString::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; + QString ls = QString::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; + QApplication::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 (QCString ("Backend")) { +} + +Backend::~Backend () {} + +void Backend::setURL (QString url) { + mrl = url; +} + +void Backend::setSubTitleURL (QString url) { + sub_mrl = url; +} + +void Backend::play (int repeat_count) { + xineapp->play (repeat_count); +} + +void Backend::stop () { + QTimer::singleShot (0, xineapp, 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, QString al) { + xineapp->setAudioLang (id, al); +} + +void Backend::setSubtitle (int id, QString sl) { + xineapp->setSubtitle (id, sl); +} + +void Backend::quit () { + delete callback; + callback = 0L; + if (running) + stop (); + else + QTimer::singleShot (0, qApp, SLOT (quit ())); +} + +bool updateConfigEntry (const QString & name, const QString & 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 (QByteArray data) { + QString err; + int line, column; + QDomDocument dom; + if (dom.setContent (data, false, &err, &line, &column)) { + if (dom.childNodes().length() == 1) { + for (QDomNode node = dom.firstChild().firstChild(); + !node.isNull (); + node = node.nextSibling ()) { + QDomNamedNodeMap attr = node.attributes (); + updateConfigEntry (attr.namedItem (attname).nodeValue (), + attr.namedItem (attvalue).nodeValue ()); + } + xine_config_save (xine, configfile); + } else + err = QString ("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) + : QApplication (_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) + QTimer::singleShot (10, this, 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 (QByteArray & buf) { + xine_cfg_entry_t entry; + QDomDocument doc; + QDomElement root = doc.createElement (QString ("document")); + for (int i = xine_config_get_first_entry (xine, &entry); + i; + i = xine_config_get_next_entry (xine, &entry)) { + QDomElement elm = doc.createElement (elmentry); + elm.setAttribute (attname, QString (entry.key)); + if (entry.type == XINE_CONFIG_TYPE_STRING || entry.type == XINE_CONFIG_TYPE_UNKNOWN) { + elm.setAttribute (atttype, valstring); + elm.setAttribute (attvalue, QString (entry.str_value)); + } else { + elm.setAttribute (attdefault, QString::number (entry.num_default)); + elm.setAttribute (attvalue, QString::number (entry.num_value)); + switch (entry.type) { + case XINE_CONFIG_TYPE_RANGE: + elm.setAttribute (atttype, valrange); + elm.setAttribute (attstart, QString::number (entry.range_min)); + elm.setAttribute (attend, QString::number (entry.range_max)); + break; + case XINE_CONFIG_TYPE_ENUM: + elm.setAttribute (atttype, valenum); + for (int i = 0; entry.enum_values[i]; i++) { + QDomElement item = doc.createElement (elmitem); + item.setAttribute (attvalue, QString (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 (QString::fromUtf8 (entry.help))); + root.appendChild (elm); + } + doc.appendChild (root); + QString exp = doc.toString (); + QCString 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 = QString ("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++) { + QString m (mrls[i]); + QString title; + if (xine_open (stream, mrls[i])) { + const char * t = xine_get_meta_info (stream, XINE_META_INFO_TITLE); + if (t && t[0]) + title = QString::fromUtf8 (t); + xine_close (stream); + } + if (callback) + callback->subMrl (m, title); + else + printf ("track %s\n", m.utf8 ().data ()); + } + mutex.unlock (); + finished (); + return; + } + + xine_gui_send_vo_data(stream, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1); + + running = 1; + QString mrlsetup = mrl; + if (!rec_mrl.isEmpty ()) { + char * rm = strdup (rec_mrl.local8Bit ()); + char *bn = basename (rm); + char *dn = dirname (rm); + if (bn) + updateConfigEntry (QString ("media.capture.save_dir"), QString::fromLocal8Bit (dn)); + mrlsetup += QString ("#save:") + QString::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)) + QApplication::postEvent(xineapp, new QEvent((QEvent::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 (); + QTimer::singleShot (10, this, SLOT (postFinished ())); +} + +void KXinePlayer::postFinished () { + QApplication::postEvent (xineapp, new QEvent ((QEvent::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 () { + QTimer::singleShot (10, this, SLOT (stop ())); +} + +void KXinePlayer::setAudioLang (int id, const QString & 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 QString & 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); + } + QTimer::singleShot (500, this, 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 (QEvent * 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 + QTimer::singleShot (0, this, 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 (); + QTimer::singleShot (500, this, 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, QString ()); + 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, QString ()); + break; + default: + return false; + } + return true; +} + +void KXinePlayer::saveState (QSessionManager & sm) { + if (callback) + sm.setRestartHint (QSessionManager::RestartNever); +} + +XineMovieParamEvent::XineMovieParamEvent(int l, int w, int h, const QStringList & a, const QStringList & s, bool ff) + : QEvent ((QEvent::Type) event_size), + length (l), width (w), height (h), alang (a), slang (s) , first_frame (ff) +{} + +XineURLEvent::XineURLEvent (const QString & u) + : QEvent ((QEvent::Type) event_url), url (u) +{} + +XineTitleEvent::XineTitleEvent (const char * t) + : QEvent ((QEvent::Type) event_title), title (QString::fromUtf8 (t)) +{ + QUrl::decode (title); +} + +XineProgressEvent::XineProgressEvent (const int p) + : QEvent ((QEvent::Type) event_progress), progress (p) +{} + +//static bool translateCoordinates (int wx, int wy, int mx, int my) { +// movie_width +class XEventThread : public QThread { +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_gui_send_vo_data(stream, 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_gui_send_vo_data (stream, 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_gui_send_vo_data (stream, 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_gui_send_vo_data(stream, 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; + QString vo_driver ("auto"); + QString 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 = QString (argv [i]); + } else if (!strcmp (argv [i], "-lang") && ++i < argc) { + slang = alang = QString (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) { + QString 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 = QString::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 = QString::fromLocal8Bit (argv [i]); + } + } + bool config_changed = !QFile (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 (QString ("input.dvd_device"), QString (dvd_device)); + if (vcd_device) + config_changed |= updateConfigEntry (QString ("input.vcd_device"), QString (vcd_device)); + if (grab_device) + config_changed |= updateConfigEntry (QString ("media.video4linux.video_device"), QString (grab_device)); + + if (config_changed) + xine_config_save (xine, configfile); + + QStringList vos = QStringList::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"); + QStringList aos = QStringList::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); + + QByteArray 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", QString (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" |