From 092be7678b67552cb3161fe162242bf8d3aeed2f Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 17 Feb 2010 00:54:13 +0000 Subject: 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 --- src/DESIGN.txt | 38 + src/Makefile.am | 80 + src/bookmarks.xml | 670 ++++++++ src/example_kjsembed.js | 38 + src/example_smil.html | 59 + src/gstplayer.cpp | 1027 +++++++++++ src/gstplayer.h | 64 + src/kmplayer.desktop | 100 ++ src/kmplayer.h | 204 +++ src/kmplayer_asx.cpp | 146 ++ src/kmplayer_asx.h | 101 ++ src/kmplayer_atom.cpp | 107 ++ src/kmplayer_atom.h | 82 + src/kmplayer_backend.h | 58 + src/kmplayer_callback.h | 51 + src/kmplayer_def.h | 69 + src/kmplayer_koffice.desktop | 15 + src/kmplayer_koffice_part.cpp | 168 ++ src/kmplayer_koffice_part.h | 85 + src/kmplayer_part.cpp | 1197 +++++++++++++ src/kmplayer_part.desktop | 88 + src/kmplayer_part.h | 176 ++ src/kmplayer_rp.cpp | 497 ++++++ src/kmplayer_rp.h | 193 +++ src/kmplayer_rss.cpp | 130 ++ src/kmplayer_rss.h | 88 + src/kmplayer_smil.cpp | 3604 +++++++++++++++++++++++++++++++++++++++ src/kmplayer_smil.h | 898 ++++++++++ src/kmplayer_xspf.cpp | 151 ++ src/kmplayer_xspf.h | 94 + src/kmplayerapp.cpp | 2296 +++++++++++++++++++++++++ src/kmplayerappsource.h | 205 +++ src/kmplayerbroadcast.cpp | 670 ++++++++ src/kmplayerbroadcast.h | 194 +++ src/kmplayerconfig.cpp | 749 ++++++++ src/kmplayerconfig.h | 204 +++ src/kmplayercontrolpanel.cpp | 703 ++++++++ src/kmplayercontrolpanel.h | 181 ++ src/kmplayerpartbase.cpp | 2047 ++++++++++++++++++++++ src/kmplayerpartbase.h | 298 ++++ src/kmplayerpartui.rc | 19 + src/kmplayerplaylist.cpp | 1842 ++++++++++++++++++++ src/kmplayerplaylist.h | 979 +++++++++++ src/kmplayerprocess.cpp | 2567 ++++++++++++++++++++++++++++ src/kmplayerprocess.h | 500 ++++++ src/kmplayerrc | 55 + src/kmplayershared.h | 264 +++ src/kmplayersource.h | 176 ++ src/kmplayertvsource.cpp | 737 ++++++++ src/kmplayertvsource.h | 218 +++ src/kmplayertypes.h | 300 ++++ src/kmplayerui.rc | 99 ++ src/kmplayervdr.cpp | 780 +++++++++ src/kmplayervdr.h | 169 ++ src/kmplayerview.cpp | 831 +++++++++ src/kmplayerview.h | 243 +++ src/main.cpp | 90 + src/moz-sdk/jni.h | 1810 ++++++++++++++++++++ src/moz-sdk/jni_md.h | 199 +++ src/moz-sdk/jri.h | 689 ++++++++ src/moz-sdk/jri_md.h | 565 ++++++ src/moz-sdk/jritypes.h | 243 +++ src/moz-sdk/npapi.h | 726 ++++++++ src/moz-sdk/npruntime.h | 397 +++++ src/moz-sdk/nptypes.h | 105 ++ src/moz-sdk/npupp.h | 1889 ++++++++++++++++++++ src/moz-sdk/obsolete/protypes.h | 252 +++ src/moz-sdk/prcpucfg.h | 716 ++++++++ src/moz-sdk/prtypes.h | 544 ++++++ src/noise.gif | Bin 0 -> 8850 bytes src/npplayer.c | 1545 +++++++++++++++++ src/playlistview.cpp | 720 ++++++++ src/playlistview.h | 174 ++ src/pluginsinfo | 31 + src/pref.cpp | 866 ++++++++++ src/pref.h | 320 ++++ src/subtrans.txt | 19 + src/transitions.txt | 29 + src/triestring.cpp | 516 ++++++ src/triestring.h | 103 ++ src/viewarea.cpp | 1691 ++++++++++++++++++ src/viewarea.h | 89 + src/xineplayer.cpp | 1239 ++++++++++++++ src/xineplayer.h | 79 + src/xvplayer.cpp | 704 ++++++++ src/xvplayer.h | 56 + 86 files changed, 44010 insertions(+) create mode 100644 src/DESIGN.txt create mode 100644 src/Makefile.am create mode 100644 src/bookmarks.xml create mode 100644 src/example_kjsembed.js create mode 100644 src/example_smil.html create mode 100644 src/gstplayer.cpp create mode 100644 src/gstplayer.h create mode 100644 src/kmplayer.desktop create mode 100644 src/kmplayer.h create mode 100644 src/kmplayer_asx.cpp create mode 100644 src/kmplayer_asx.h create mode 100644 src/kmplayer_atom.cpp create mode 100644 src/kmplayer_atom.h create mode 100644 src/kmplayer_backend.h create mode 100644 src/kmplayer_callback.h create mode 100644 src/kmplayer_def.h create mode 100644 src/kmplayer_koffice.desktop create mode 100644 src/kmplayer_koffice_part.cpp create mode 100644 src/kmplayer_koffice_part.h create mode 100644 src/kmplayer_part.cpp create mode 100644 src/kmplayer_part.desktop create mode 100644 src/kmplayer_part.h create mode 100644 src/kmplayer_rp.cpp create mode 100644 src/kmplayer_rp.h create mode 100644 src/kmplayer_rss.cpp create mode 100644 src/kmplayer_rss.h create mode 100644 src/kmplayer_smil.cpp create mode 100644 src/kmplayer_smil.h create mode 100644 src/kmplayer_xspf.cpp create mode 100644 src/kmplayer_xspf.h create mode 100644 src/kmplayerapp.cpp create mode 100644 src/kmplayerappsource.h create mode 100644 src/kmplayerbroadcast.cpp create mode 100644 src/kmplayerbroadcast.h create mode 100644 src/kmplayerconfig.cpp create mode 100644 src/kmplayerconfig.h create mode 100644 src/kmplayercontrolpanel.cpp create mode 100644 src/kmplayercontrolpanel.h create mode 100644 src/kmplayerpartbase.cpp create mode 100644 src/kmplayerpartbase.h create mode 100644 src/kmplayerpartui.rc create mode 100644 src/kmplayerplaylist.cpp create mode 100644 src/kmplayerplaylist.h create mode 100644 src/kmplayerprocess.cpp create mode 100644 src/kmplayerprocess.h create mode 100644 src/kmplayerrc create mode 100644 src/kmplayershared.h create mode 100644 src/kmplayersource.h create mode 100644 src/kmplayertvsource.cpp create mode 100644 src/kmplayertvsource.h create mode 100644 src/kmplayertypes.h create mode 100644 src/kmplayerui.rc create mode 100644 src/kmplayervdr.cpp create mode 100644 src/kmplayervdr.h create mode 100644 src/kmplayerview.cpp create mode 100644 src/kmplayerview.h create mode 100644 src/main.cpp create mode 100644 src/moz-sdk/jni.h create mode 100644 src/moz-sdk/jni_md.h create mode 100644 src/moz-sdk/jri.h create mode 100644 src/moz-sdk/jri_md.h create mode 100644 src/moz-sdk/jritypes.h create mode 100644 src/moz-sdk/npapi.h create mode 100644 src/moz-sdk/npruntime.h create mode 100644 src/moz-sdk/nptypes.h create mode 100644 src/moz-sdk/npupp.h create mode 100644 src/moz-sdk/obsolete/protypes.h create mode 100644 src/moz-sdk/prcpucfg.h create mode 100644 src/moz-sdk/prtypes.h create mode 100644 src/noise.gif create mode 100644 src/npplayer.c create mode 100644 src/playlistview.cpp create mode 100644 src/playlistview.h create mode 100644 src/pluginsinfo create mode 100644 src/pref.cpp create mode 100644 src/pref.h create mode 100644 src/subtrans.txt create mode 100644 src/transitions.txt create mode 100644 src/triestring.cpp create mode 100644 src/triestring.h create mode 100644 src/viewarea.cpp create mode 100644 src/viewarea.h create mode 100644 src/xineplayer.cpp create mode 100644 src/xineplayer.h create mode 100644 src/xvplayer.cpp create mode 100644 src/xvplayer.h (limited to 'src') diff --git a/src/DESIGN.txt b/src/DESIGN.txt new file mode 100644 index 0000000..e0e3a31 --- /dev/null +++ b/src/DESIGN.txt @@ -0,0 +1,38 @@ +The core of kmplayer is in kmplayerpartbase.x. PartBase keeps +the list of Source objects (dvd/vcd/url/..) and Process objects +(mplayer/xine/gst/xv), controls the View or respond to its signals. Both +application as kpart (for plugin) have one PartBase. However, in case of +plugin for khtml, it's possible one PartBase controls multible View +objects (see tests/controls.html). + +The View is the parent of ViewArea, PlayList and InfoWindow. ViewArea is +the parent of Viewer (the output for the backend players) and +ControlPanel. +In case of smil animations, the Viewer widget can be hidden or made +smaller so ViewArea background is where the rendering is done. +Classes in kmplayerplaylist.x are actually base for the XML playlist +formats (smil/asx/rss/..). + +There is always one Source object active. A Source object sets up the +interface to the user as far possible, handling playlists and launching +backends. This is not fully worked out yet, eg. URLSource should be able +to launch multible backends for smil. Which probably means that PartBase +should have a list of Process factories and Source objects a list of +running Process objects. + +Backends are instances of Process and should be simple, just passing +data from/to external processes. A Recorder object is also a Process. +Though for mplayer, there is quite some code for output parsing. + +The XML classes and parser provide a quick way for storing any XML file +in the playlist. Tree nodes build the tree themselves and recognized +multimedia elements more or less play the playlist themselves too. +The parser is build to recover from all kinds of typos. This is because +ASX is quite often full of XML errors that made other parsers give up, +eg. I've seen something like "Laurel & Hardy< / title>". + +KMPlayerPart and KMPlayerApp are classes that use the above for plugin +and application. + +Finally there is also a Settings class for general usage and for +launching the configure dialog. diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..c481b8d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,80 @@ +AM_CPPFLAGS= -I$(kde_includes)/kio $(CFLAGS_GST) $(all_includes) $(LIBCAIRO_CFLAGS) $(LIBNSPR_CFLAGS) $(LIBDBUS_CFLAGS) + +METASOURCES= AUTO + +lib_LTLIBRARIES= libkmplayercommon.la + +libkmplayercommon_la_SOURCES = viewarea.cpp kmplayerview.cpp playlistview.cpp kmplayercontrolpanel.cpp kmplayerconfig.cpp pref.cpp kmplayerprocess.cpp kmplayer_callback.skel kmplayer_backend.stub kmplayerpartbase.cpp kmplayerplaylist.cpp kmplayer_asx.cpp kmplayer_smil.cpp kmplayer_rp.cpp kmplayer_rss.cpp kmplayer_atom.cpp kmplayer_xspf.cpp triestring.cpp kmplayerpartbase.skel +libkmplayercommon_la_LDFLAGS = -avoid-version $(all_libraries) +libkmplayercommon_la_LIBADD = -lkmediaplayer $(LIB_KPARTS) $(LIB_KUTILS) $(LIB_EXPAT) -lm $(LIBCAIRO_LIBS) $(LIBQTDBUS) + +if include_koffice_support +kofficeplugin_lib= libkmplayerkofficepart.la +SERVICES_KOFFICE = kmplayer_koffice.desktop +endif + +kde_module_LTLIBRARIES= libkmplayerpart.la $(kofficeplugin_lib) + +libkmplayerpart_la_SOURCES= kmplayer_part.cpp +libkmplayerpart_la_LDFLAGS= -avoid-version $(all_libraries) $(KDE_RPATH) +libkmplayerpart_la_LIBADD= libkmplayercommon.la + +libkmplayerkofficepart_la_SOURCES=kmplayer_koffice_part.cpp +libkmplayerkofficepart_la_LDFLAGS= -avoid-version $(all_libraries) $(KDE_RPATH) +libkmplayerkofficepart_la_LIBADD= libkmplayercommon.la $(LIB_KOFFICE) + +kdeinit_LTLIBRARIES=kmplayer.la +kmplayer_la_SOURCES= main.cpp kmplayerapp.cpp kmplayertvsource.cpp kmplayerbroadcast.cpp kmplayervdr.cpp +kmplayer_la_LIBADD= libkmplayercommon.la +kmplayer_la_LDFLAGS= -module $(KDE_PLUGIN) + +EXTRA_PROGRAMS = kxineplayer kxvplayer kgstplayer +if include_kxineplayer +kxineplayer_app = kxineplayer +endif +if include_kgstplayer +kgstplayer_app = kgstplayer +endif +if include_knpplayer +knpplayer_app = knpplayer +endif + +bin_PROGRAMS= $(kxineplayer_app) kxvplayer $(kgstplayer_app) $(knpplayer_app) + +noinst_LTLIBRARIES = libkmplayerbackend.la +libkmplayerbackend_la_SOURCES = kmplayer_backend.skel kmplayer_callback.stub + +kxineplayer_LDADD= libkmplayerbackend.la $(LIB_XINE) -lDCOP +kxineplayer_CFLAGS= $(CFLAGS_XINE) +kxineplayer_LDFLAGS= $(all_libraries) $(KDE_RPATH) +kxineplayer_SOURCES= xineplayer.cpp + +kxvplayer_LDADD= libkmplayerbackend.la -lDCOP -lXv +kxvplayer_LDFLAGS= $(all_libraries) $(KDE_RPATH) +kxvplayer_SOURCES= xvplayer.cpp + +kgstplayer_LDADD= libkmplayerbackend.la $(LIB_GST) $(LIB_GST_PLUGINS) -lgstinterfaces-0.10 -lDCOP +kgstplayer_LDFLAGS= $(all_libraries) $(KDE_RPATH) +kgstplayer_SOURCES= gstplayer.cpp + +knpplayer_LDADD= $(LIBNSPR_LIBS) +knpplayer_SOURCES= npplayer.c + +xdg_apps_DATA = kmplayer.desktop + +kde_services_DATA = kmplayer_part.desktop $(SERVICES_KOFFICE) + +rc_DATA = kmplayerui.rc kmplayerpartui.rc +rcdir = $(kde_datadir)/kmplayer + +conf_DATA = kmplayerrc +confdir = $(kde_confdir) + +appsdatadir=$(kde_datadir)/kmplayer +appsdata_DATA= bookmarks.xml pluginsinfo noise.gif + +dummy.cpp: + echo > dummy.cpp + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kmplayer.pot diff --git a/src/bookmarks.xml b/src/bookmarks.xml new file mode 100644 index 0000000..bf4c89a --- /dev/null +++ b/src/bookmarks.xml @@ -0,0 +1,670 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE xbel> +<xbel folded="yes" > + <folder folded="yes" icon="bookmark_folder" > + <title>South America + + Brazil + + Bloomberg TV Brazil + + + + + Asia + + TV + + Bloomberg TV Asia-Pacific + + + Bloomberg TV Japan + + + + + Europe + + belgium + + flanders + + Radio 1 + + + Sporza + + + Radio 2 Antwerpen + + + Radio 2 Vlaams-Brabant + + + Radio 2 Limburg + + + Radio 2 Oost-Vlaanderen + + + Radio 2 West-Vlaanderen + + + Klara + + + Klara Continuo + + + Studio Brussel + + + Donna + + + Donna Hitbits + + + RVI + + + Urgent.fm + + + Be One + + + Radio Contact + + + Q-Music + + + Topradio + + + 4fm + + + + + czech republic + + radio valc + + radio valc live + + + radio valc 1 gold + + + radio valc 2 country + + + radio valc 3 hit + + + radio valc 4 rock + + + radio valc 5 classic + + + radio valc 6 valcarka + + + radio valc 7 folk + + + + cesky rozhlas + + cro1 radiozurnal + + + cro2 praha + + + cro3 vltava + + + cro ceske budejovice + + + cro hradec kralove + + + cro olomouc + + + cro ostrava + + + cro plzen + + + cro stredni cechy + + + + radio akropolis + + + krokodyl + + + joe + + + regina + + + kiss hady + + + proglas + + + country radio + + + proton + + + radio beat + + + expresradio + + + kiss 98 fm + + + radio1 + + + kiss publikum + + + radio apollo + + + evropa 2 + + + radio crystal + + + northmusic + + + radio sumava + + + radio karolina + + + fajn radio hity + + + kiss fm + + + kiss morava + + + cerna hora + + + radio fm plus + + + helax + + + radio impuls + + + radio info + + + radio life fajn + + + radio relax + + + + denmark + + P1 + + + P2 + + + P3 + + + Kanal 94 + + + Radio Fyn + + + Bornholms Radio + + + Regionalen + + + Københavns Radio + + + Radio Syd + + + Østjyllands Radio + + + Radio Midt & Vest + + + DR Barometer + + + DR Boogieradio + + + DR Erhverv + + + DR Ghetto + + + DR Gyldne Genhør + + + DR Jazz + + + DR Klassisk + + + DR Nyheder + + + DR Rock + + + DR Soft + + + DR Sport + + + + + TV + + I Télévision + + + Bloomberg TV France + + + bbc news + + + france + + europe1 + + + cherie FM + + + vibration + + + rfi + + + france-inter + + + france info + + + rmc + + + rtl + + + nrj + + + nostalgie + + + fun + + + bbc 7 + + + abf + + + europe 2 + + + fip + + + franceculture + + + rfm + + + rtl2 + + + skyrock + + + rireet chansons + + + france musique + + + Let's Go Zik + + + + germany + + TV + + Bloomberg TV Germany + + + GIGA TV + + + + hit radio antenne 1 + + + radio hamburg + + + 89.0 rtl + + + 107.8 star fm + + + rockland sachsen-anhalt + + + + greece + + Cosmoradio + + + + hungary + + Tilos Radio + + + Csaba Radio + + + Jazz Radio + + + + ireland + + Live Ireland + + + + italy + + TV + + Bloomberg TV Italy + + + + Company + + + DeeJay + + + M2O + + + Radio Uno + + + Radio Due + + + Radio Tre + + + + macedonia + + City Radio + + + + netherlands + + NOS Journaal + + + DBS Radio + + + + norway + + metal express + + + + russia + + Europa Plus + + + Red Army Radio + + + + san marino + + san marino + + + + slovakia + + TV + + joj + + + markíza + + + + flash + + + RockFM + + + zet + + + slovensko + + + twist radio + + + Radio Slobodna Europa + + + BBC World Service Slovak + + + fun radio + + + radio okey + + + lumen + + + duha + + + nradio + + + frontinus + + + + slovenia + + Libra Radio + + + + spain + + TV + + Bloomberg TV Spain + + + + Ona Mallorca + + + Alpicat Radio + + + + united kingdom + + virgin radio + + 1215AM + + + 1215AM (broadband) + + + classic rock + + + classic rock (broadband) + + + groove + + + groove (broadband) + + + + TV + + Bloomberg TV UK + + + + URN + + + + + North America + + USA + + TV + + Bloomberg TV US + + + Bloomberg TV US (broadband) + + + + NH + + WNTK + + + WUNH + + + + NY + + Digitally Imported - EuroDance + + + Digitally Imported - Modern Jazz + + + MostlyClassical.com + + + + kqrx 95x + + + wber 90.5 fm + + + the coast kozt fm + + + + Canada + + CIZZ Zed 99 + + + CKGY Country + + + CBC - radioONE + + + + Mexico + + XEMA B15 + + + + diff --git a/src/example_kjsembed.js b/src/example_kjsembed.js new file mode 100644 index 0000000..3412398 --- /dev/null +++ b/src/example_kjsembed.js @@ -0,0 +1,38 @@ +#!/usr/bin/env kjscmd + +/** + * Simple video widget added to your own KJSEmbed application that plays a movie + */ + +// Create main view +var mw = new KMainWindow(); +var box = new QVBox( mw ); +mw.setCentralWidget(box); + +var part = Factory.createROPart("application/x-kmplayer", box, "video_win"); + +/** + * KJS Bindings for KDE-3.3 also allows passing extra arguments to the part + * This allows to split of the control panel from the video widget: + +var part = Factory.createROPart("application/x-kmplayer", "'KParts/ReadOnlyPart' in ServiceTypes", box, "video_win", ["CONSOLE=foo", "CONTROLS=ImageWindow"]); +var part1 = Factory.createROPart("application/x-kmplayer", "'KParts/ReadOnlyPart' in ServiceTypes", box, "control_win", ["CONSOLE=foo", "CONTROLS=ControlPanel"]); + + * The order in which the part are created doesn't really matter. Also on which + * part openURL is called should not make a difference + */ + +/** + * There are at least two ways to communicate with kmplayer part + * 1. use the slots of the part (see below), an array of slots is returned by + * part.slots() + * 2. use kmplayer's DCOP interface + */ + +var stopbutton = new QPushButton( box, 'Stop' ); +stopbutton.text = "&Stop"; +mw.connect( stopbutton, 'clicked()', part, 'stop()' ); +part.openURL( "file:/home/koos/doc/example.avi" ); + +mw.show(); +application.exec(); diff --git a/src/example_smil.html b/src/example_smil.html new file mode 100644 index 0000000..c7a29da --- /dev/null +++ b/src/example_smil.html @@ -0,0 +1,59 @@ +crash.html + + + + + diff --git a/src/gstplayer.cpp b/src/gstplayer.cpp new file mode 100644 index 0000000..092a8b2 --- /dev/null +++ b/src/gstplayer.cpp @@ -0,0 +1,1027 @@ +/* This file is part of the KMPlayer application + Copyright (C) 2004 Koos Vriezen + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kmplayer_backend.h" +#include "kmplayer_callback_stub.h" +#include "kmplayer_callback.h" +#include "gstplayer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static char configfile[2048]; + +static Display *display; +static KGStreamerPlayer *gstapp; +static KMPlayer::Callback_stub * callback; +static Window wid; +static QMutex mutex (true); +static bool window_created = true; +static bool wants_config; +static bool verbose; +static bool notified_playing; +static int running; +static int movie_width; +static int movie_height; +static int movie_length; +static int repeat_count; +static int screen; +static const int event_finished = QEvent::User; +static const int event_playing = QEvent::User + 1; +static const int event_size = QEvent::User + 2; +static const int event_eos = QEvent::User + 3; +static const int event_progress = QEvent::User + 4; +static const int event_error = QEvent::User + 5; +static const int event_video = QEvent::User + 6; +static QString mrl; +static QString sub_mrl; +static const char *ao_driver; +static const char *vo_driver; +static const char *playbin_name = "player"; +static const char *dvd_device; +static const char *vcd_device; +static GstElement *gst_elm_play; +static GstBus *gst_bus; +static unsigned int /*GstMessageType*/ ignore_messages_mask; +static GstXOverlay *xoverlay; +static GstColorBalance *color_balance; +static gulong gst_bus_sync; +static gulong gst_bus_async; +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" { + // nothing yet +} // extern "C" + + +static bool gstPollForStateChange (GstElement *, GstState, gint64=GST_SECOND/2); + +static void +cb_error (GstElement * play, + GstElement * /*src*/, + GError *err, + const char *debug, + gpointer /*data*/) +{ + fprintf (stderr, "cb_error: %s %s\n", err->message, debug); + if (GST_STATE (play) == GST_STATE_PLAYING) + gst_element_set_state (play, GST_STATE_READY); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type)event_finished)); +} + +// NULL -> READY -> PAUSED -> PLAYING + +static void +gstCapsSet (GstPad *pad, + GParamSpec * /*pspec*/, + gpointer /*data*/) +{ + GstCaps *caps = gst_pad_get_negotiated_caps (pad); + if (!caps) + return; + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_video)); + const GstStructure * s = gst_caps_get_structure (caps, 0); + if (s) { + const GValue *par; + + gst_structure_get_int (s, "width", &movie_width); + gst_structure_get_int (s, "height", &movie_height); + if ((par = gst_structure_get_value (s, "pixel-aspect-ratio"))) { + int num = gst_value_get_fraction_numerator (par), + den = gst_value_get_fraction_denominator (par); + + if (num > den) + movie_width = (int) ((float) num * movie_width / den); + else + movie_height = (int) ((float) den * movie_height / num); + } + QApplication::postEvent (gstapp, new GstSizeEvent (movie_length, movie_width, movie_height)); + } + gst_caps_unref (caps); +} + +static void gstStreamInfo (GObject *, GParamSpec *, gpointer /*data*/) { + GstPad *videopad = 0L; + GList *streaminfo = 0L; + + fprintf (stderr, "gstStreamInfo\n"); + g_object_get (gst_elm_play, "stream-info", &streaminfo, NULL); + streaminfo = g_list_copy (streaminfo); + g_list_foreach (streaminfo, (GFunc) g_object_ref, NULL); + for ( ; streaminfo != NULL; streaminfo = streaminfo->next) { + GObject *info = G_OBJECT (streaminfo->data); + gint type; + GParamSpec *pspec; + GEnumValue *val; + + if (!info) + continue; + g_object_get (info, "type", &type, NULL); + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(info), "type"); + val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type); + + if (!g_strcasecmp (val->value_nick, "video")) + if (!videopad) { + g_object_get (info, "object", &videopad, NULL); + gstCapsSet (GST_PAD (videopad), 0L, 0L); + g_signal_connect (videopad, "notify::caps", G_CALLBACK (gstCapsSet), 0L); + } + } + + GstMessage * msg = gst_message_new_application (GST_OBJECT (gst_elm_play), + gst_structure_new ("notify-streaminfo", NULL)); + gst_element_post_message (gst_elm_play, msg); + g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL); + g_list_free (streaminfo); +} + +static void gstSource (GObject *, GParamSpec *, gpointer /*data*/) { + GObject *source = 0L; + fprintf (stderr, "gstSource\n"); + g_object_get (gst_elm_play, "source", &source, NULL); + if (!source) + return; + GObjectClass *klass = G_OBJECT_GET_CLASS (source); + if (mrl.startsWith ("dvd://") && dvd_device) { + if (g_object_class_find_property (klass, "device")) + g_object_set (source, "device", dvd_device, NULL); + } else if (mrl.startsWith ("vcd://") && vcd_device) { + if (g_object_class_find_property (klass, "device")) + g_object_set (source, "device", vcd_device, NULL); + } + g_object_unref (source); +} + +static void gstGetDuration () { + GstFormat fmt = GST_FORMAT_TIME; + gint64 len = -1; // usec + if (gst_element_query_duration (gst_elm_play, &fmt, &len)) + if (movie_length != len / (GST_MSECOND * 100)) { + movie_length = len / (GST_MSECOND * 100); + fprintf (stderr, "new length %d\n", movie_length); + QApplication::postEvent (gstapp, new GstSizeEvent (movie_length, movie_width, movie_height)); + } +} + +static void gstTag (const GstTagList *, const gchar *tag, gpointer) { + fprintf (stderr, "Tag: %s\n", tag); +} + +//static bool gstStructure (GQuark field_id, const GValue *value, gpointer user_data); + +static void gstBusMessage (GstBus *, GstMessage * message, gpointer) { + GstMessageType msg_type = GST_MESSAGE_TYPE (message); + /* somebody else is handling the message, probably in gstPolForStateChange*/ + if (ignore_messages_mask & msg_type) + return; + switch (msg_type) { + case GST_MESSAGE_ERROR: + fprintf (stderr, "error msg\n"); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_error)); + if (gst_elm_play) { + gst_element_set_state (gst_elm_play, GST_STATE_NULL); + //gstPollForStateChange (gst_elm_play, GST_STATE_NULL); + } + break; + case GST_MESSAGE_WARNING: + fprintf (stderr, "warning msg\n"); + break; + case GST_MESSAGE_TAG: { + GstTagList *tag_list; + //fprintf (stderr, "tag msg\n"); + gst_message_parse_tag (message, &tag_list); + gst_tag_list_foreach (tag_list, gstTag, 0L); + gst_tag_list_free (tag_list); + break; + } + case GST_MESSAGE_EOS: + fprintf (stderr, "eos msg\n"); + gst_element_set_state (gst_elm_play, GST_STATE_READY); + break; + case GST_MESSAGE_BUFFERING: { + gint percent = 0; + gst_structure_get_int (message->structure, "buffer-percent", &percent); + QApplication::postEvent (gstapp, new GstProgressEvent (percent)); + //fprintf (stderr, "Buffering message (%u%%)\n", percent); + break; + } + case GST_MESSAGE_APPLICATION: { + const char * msg = gst_structure_get_name (message->structure); + fprintf (stderr, "app msg %s\n", msg ? msg : ""); + //gst_structure_foreach (message->structure, gstStructure, 0L); + break; + } + case GST_MESSAGE_STATE_CHANGED: { + GstState old_state, new_state; + //gchar *src_name = gst_object_get_name (message->src); + gst_message_parse_state_changed(message, &old_state, &new_state,0L); + //fprintf (stderr, "%s changed state from %s to %s\n", src_name, gst_element_state_get_name (old_state), gst_element_state_get_name (new_state)); + if (GST_IS_ELEMENT (message->src) && + GST_ELEMENT (message->src) == gst_elm_play) { + if (old_state == GST_STATE_PAUSED && + new_state >= GST_STATE_PLAYING) { + gstGetDuration (); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_playing)); + } else if (old_state >= GST_STATE_PAUSED && + new_state <= GST_STATE_READY) { + if (repeat_count-- > 0 && + (gst_element_set_state(gst_elm_play, GST_STATE_PAUSED), + gstPollForStateChange(gst_elm_play, GST_STATE_PAUSED))) + gst_element_set_state(gst_elm_play, GST_STATE_PLAYING); + else + QApplication::postEvent (gstapp, + new QEvent ((QEvent::Type) event_finished)); + } + } + //g_free (src_name); + break; + } + case GST_MESSAGE_DURATION: + gstGetDuration (); + break; + case GST_MESSAGE_CLOCK_PROVIDE: + case GST_MESSAGE_CLOCK_LOST: + case GST_MESSAGE_NEW_CLOCK: + case GST_MESSAGE_STATE_DIRTY: + break; + default: + fprintf (stderr, "Unhandled msg %s (0x%x)\n", + gst_message_type_get_name (msg_type), msg_type); + break; + } +} + +static void gstMessageElement (GstBus *, GstMessage *msg, gpointer /*data*/) { + if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) { + fprintf (stderr, "prepare-xwindow-id\n"); + if (xoverlay) + gst_x_overlay_set_xwindow_id (xoverlay, wid); + } +} + +static bool gstPollForStateChange (GstElement *element, GstState state, gint64 timeout) { + /*GstMessageType*/ unsigned int events, saved_events; + GstBus *bus = gst_element_get_bus (element); + GError **error = 0L; + + events = GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS; + saved_events = ignore_messages_mask; + + if (element && element == gst_elm_play) { + /* we do want the main handler to process state changed messages for + * playbin as well, otherwise it won't hook up the timeout etc. */ + ignore_messages_mask |= (events ^ GST_MESSAGE_STATE_CHANGED); + } else { + ignore_messages_mask |= events; + } + + while (true) { + GstMessage *message; + GstElement *src; + + message = gst_bus_poll (bus, (GstMessageType) events, timeout); + if (!message) + goto timed_out; + + src = (GstElement*)GST_MESSAGE_SRC (message); + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_STATE_CHANGED: { + GstState olds, news, pending; + if (src == element) { + gst_message_parse_state_changed (message, &olds, &news, &pending); + if (news == state) { + gst_message_unref (message); + goto success; + } + } + break; + } + case GST_MESSAGE_ERROR: { + gchar *debug = NULL; + GError *gsterror = NULL; + gst_message_parse_error (message, &gsterror, &debug); + fprintf (stderr, "Error: %s (%s)\n", gsterror->message, debug); + gst_message_unref (message); + g_error_free (gsterror); + g_free (debug); + goto error; + } + case GST_MESSAGE_EOS: { + gst_message_unref (message); + goto error; + } + default: + g_assert_not_reached (); + break; + } + gst_message_unref (message); + } + g_assert_not_reached (); + +success: + /* state change succeeded */ + fprintf (stderr, "state change to %s succeeded\n", gst_element_state_get_name (state)); + ignore_messages_mask = saved_events; + return true; + +timed_out: + /* it's taking a long time to open -- just tell totem it was ok, this allows + * the user to stop the loading process with the normal stop button */ + fprintf (stderr, "state change to %s timed out, returning success and handling errors asynchroneously\n", gst_element_state_get_name (state)); + ignore_messages_mask = saved_events; + return true; + +error: + fprintf (stderr, "error while waiting for state change to %s: %s\n", + gst_element_state_get_name (state), + (error && *error) ? (*error)->message : "unknown"); + /* already set *error */ + ignore_messages_mask = saved_events; + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_error)); + return false; +} + +//----------------------------------------------------------------------------- + +GstSizeEvent::GstSizeEvent (int l, int w, int h) + : QEvent ((QEvent::Type) event_size), + length (l), width (w), height (h) +{} + +GstProgressEvent::GstProgressEvent (const int p) + : QEvent ((QEvent::Type) event_progress), progress (p) +{} + +//----------------------------------------------------------------------------- + +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) { + gstapp->play (repeat); +} + +void Backend::stop () { + QTimer::singleShot (0, gstapp, SLOT (stop ())); +} + +void Backend::pause () { + gstapp->pause (); +} + +void Backend::seek (int v, bool /*absolute*/) { + gstapp->seek (v); +} + +void Backend::hue (int h, bool) { + gstapp->hue (h); +} + +void Backend::saturation (int s, bool) { + gstapp->saturation (s); +} + +void Backend::contrast (int c, bool) { + gstapp->contrast (c); +} + +void Backend::brightness (int b, bool) { + gstapp->brightness (b); +} + +void Backend::volume (int v, bool) { + gstapp->volume (v); +} + +void Backend::frequency (int) { +} + +void Backend::setAudioLang (int, QString) { +} + +void Backend::setSubtitle (int, QString) { +} + +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 ()); + return true; +} + +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 ()); + } + } else + err = QString ("invalid data"); + } + if (callback) + callback->errorMessage (0, err);*/ +} + +bool Backend::isPlaying () { + mutex.lock (); + bool b = gst_elm_play && (GST_STATE (gst_elm_play) == GST_STATE_PLAYING); + mutex.unlock (); + return b; +} + +KGStreamerPlayer::KGStreamerPlayer (int _argc, char ** _argv) + : QApplication (_argc, _argv, false) { +} + +void KGStreamerPlayer::init () { + int xpos = 0; + int ypos = 0; + int width = 320; + int height = 200; + + XLockDisplay(display); + if (window_created) + wid = XCreateSimpleWindow(display, XDefaultRootWindow(display), + xpos, ypos, width, height, 1, 0, 0); + fprintf (stderr, "init wid %u created:%d\n", wid, window_created); + XSelectInput (display, wid, + (PointerMotionMask | ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask)); // | SubstructureNotifyMask)); + + if (window_created) { + //fprintf (stderr, "map %lu\n", wid); + XMapRaised(display, wid); + XSync(display, False); + } + XUnlockDisplay(display); +} + +KGStreamerPlayer::~KGStreamerPlayer () { + if (window_created) { + XLockDisplay (display); + fprintf (stderr, "unmap %lu\n", wid); + XUnmapWindow (display, wid); + XDestroyWindow(display, wid); + XSync (display, False); + XUnlockDisplay (display); + } + gstapp = 0L; +} + +void getConfigEntries (QByteArray & buf) { + QDomDocument doc; + QDomElement root = doc.createElement (QString ("document")); + doc.appendChild (root); + QCString exp = doc.toCString (); + buf = exp; + buf.resize (exp.length ()); // strip terminating \0 +} + +void KGStreamerPlayer::play (int repeat) { + GstElement *element; + GstElement *videosink = 0L; + GstElement *audiosink = 0L; + bool success; + fprintf (stderr, "play %s\n", mrl.isEmpty() ? "" : mrl.ascii ()); + if (gst_elm_play) { + if (GST_STATE (gst_elm_play) == GST_STATE_PAUSED) { + gst_element_set_state (gst_elm_play, GST_STATE_PLAYING); + gstPollForStateChange (gst_elm_play, GST_STATE_PLAYING); + } + return; + } + notified_playing = false; + if (mrl.isEmpty ()) + return; + gchar *uri, *sub_uri = 0L; + movie_length = movie_width = movie_height = 0; + mutex.lock (); + gst_elm_play = gst_element_factory_make ("playbin", playbin_name); + if (!gst_elm_play) { + fprintf (stderr, "couldn't create playbin\n"); + goto fail; + } + ignore_messages_mask = 0; + gst_bus = gst_element_get_bus (gst_elm_play); + + gst_bus_add_signal_watch (gst_bus); + + gst_bus_async = g_signal_connect (gst_bus, "message", + G_CALLBACK (gstBusMessage), 0L); + if (ao_driver && !strncmp (ao_driver, "alsa", 4)) + audiosink = gst_element_factory_make ("alsasink", "audiosink"); + else if (ao_driver && !strncmp (ao_driver, "arts", 4)) + audiosink = gst_element_factory_make ("artsdsink", "audiosink"); + else if (ao_driver && !strncmp (ao_driver, "esd", 3)) + audiosink = gst_element_factory_make ("esdsink", "audiosink"); + else + audiosink = gst_element_factory_make ("osssink", "audiosink"); + if (!audiosink) + goto fail; + if (vo_driver && !strncmp (vo_driver, "xv", 2)) + videosink = gst_element_factory_make ("xvimagesink", "videosink"); + else + videosink = gst_element_factory_make ("ximagesink", "videosink"); + if (!videosink) + goto fail; + if (GST_IS_BIN (videosink)) + element = gst_bin_get_by_interface (GST_BIN (videosink), + GST_TYPE_X_OVERLAY); + else + element = videosink; + if (GST_IS_X_OVERLAY (element)) { + xoverlay = GST_X_OVERLAY (element); + gst_x_overlay_set_xwindow_id (xoverlay, wid); + } + gst_element_set_bus (videosink, gst_bus); + gst_element_set_state (videosink, GST_STATE_READY); + success = gstPollForStateChange (videosink, GST_STATE_READY); + //if (!success) { + /* Drop this video sink */ + // gst_element_set_state (videosink, GST_STATE_NULL); + // gst_object_unref (videosink); + if (audiosink) { + gst_element_set_bus (audiosink, gst_bus); + gst_element_set_state (audiosink, GST_STATE_READY); + success = gstPollForStateChange (audiosink, GST_STATE_READY); + } + g_object_set (G_OBJECT (gst_elm_play), + "video-sink", videosink, + "audio-sink", audiosink, + NULL); + gst_bus_set_sync_handler (gst_bus, gst_bus_sync_signal_handler, 0L); + gst_bus_sync = g_signal_connect (gst_bus, "sync-message::element", + G_CALLBACK (gstMessageElement), 0L); + g_signal_connect (gst_elm_play, "notify::source", + G_CALLBACK (gstSource), 0L); + g_signal_connect (gst_elm_play, "notify::stream-info", + G_CALLBACK (gstStreamInfo), 0L); + if (GST_IS_COLOR_BALANCE (videosink)) + color_balance = GST_COLOR_BALANCE (videosink); + + if (GST_STATE (gst_elm_play) > GST_STATE_READY) + gst_element_set_state (gst_elm_play, GST_STATE_READY); + + if (mrl.startsWith (QChar ('/'))) + mrl = QString ("file://") + mrl; + uri = g_strdup (mrl.local8Bit ()); + g_object_set (gst_elm_play, "uri", uri, NULL); + if (!sub_mrl.isEmpty ()) { + if (sub_mrl.startsWith (QChar ('/'))) + sub_mrl = QString ("file://") + sub_mrl; + sub_uri = g_strdup (sub_mrl.local8Bit ()); + g_object_set (gst_elm_play, "suburi", sub_uri, NULL); + g_free (sub_uri); + } + repeat_count = repeat; + mutex.unlock (); + gst_element_set_state (gst_elm_play, GST_STATE_PAUSED); + if (gstPollForStateChange (gst_elm_play, GST_STATE_PAUSED)) { + gst_element_set_state (gst_elm_play, GST_STATE_PLAYING); + gstPollForStateChange (gst_elm_play, GST_STATE_PLAYING); + } + g_free (uri); + QTimer::singleShot (500, this, SLOT (updatePosition ())); + return; +fail: + if (videosink) { + gst_element_set_state (videosink, GST_STATE_NULL); + gst_object_unref (videosink); + } + if (audiosink) { + gst_element_set_state (audiosink, GST_STATE_NULL); + gst_object_unref (audiosink); + } + mutex.unlock (); + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type)event_finished)); +} + +void KGStreamerPlayer::pause () { + mutex.lock (); + if (gst_elm_play) { + GstState state = GST_STATE (gst_elm_play) == GST_STATE_PLAYING ? + GST_STATE_PAUSED : GST_STATE_PLAYING; + gst_element_set_state (gst_elm_play, state); + gstPollForStateChange (gst_elm_play, state); + } + mutex.unlock (); +} + +void KGStreamerPlayer::stop () { + fprintf (stderr, "stop %s\n", mrl.isEmpty () ? "" : mrl.ascii ()); + mutex.lock (); + repeat_count = 0; + if (gst_elm_play) { + GstState current_state; + gst_element_get_state (gst_elm_play, ¤t_state, NULL, 0); + if (current_state > GST_STATE_READY) { + gst_element_set_state (gst_elm_play, GST_STATE_READY); + mutex.unlock (); + gstPollForStateChange (gst_elm_play, GST_STATE_READY, -1); + mutex.lock (); + } + gst_element_set_state (gst_elm_play, GST_STATE_NULL); + gst_element_get_state (gst_elm_play, NULL, NULL, -1); + } + mutex.unlock (); + if (!gst_elm_play || (gst_elm_play && !notified_playing)) + QApplication::postEvent (gstapp, new QEvent ((QEvent::Type) event_finished)); +} + +void KGStreamerPlayer::finished () { + QTimer::singleShot (10, this, SLOT (stop ())); +} + +static void adjustColorSetting (const char * channel, int val) { + //fprintf (stderr, "adjustColorSetting %s\n", channel); + mutex.lock (); + if (color_balance) { + for (const GList *item =gst_color_balance_list_channels (color_balance); + item != NULL; item = item->next) { + GstColorBalanceChannel *chan = (GstColorBalanceChannel*) item->data; + + if (!strstr (chan->label, channel)) + gst_color_balance_set_value (color_balance, chan, + ((val + 100) * (chan->max_value - chan->min_value)/200 + chan->min_value)); + } + } + mutex.unlock (); +} + +void KGStreamerPlayer::saturation (int s) { + adjustColorSetting ("SATURATION", s); +} + +void KGStreamerPlayer::hue (int h) { + adjustColorSetting ("HUE", h); +} + +void KGStreamerPlayer::contrast (int c) { + adjustColorSetting ("CONTRAST", c); +} + +void KGStreamerPlayer::brightness (int b) { + adjustColorSetting ("BRIGHTNESS", b); +} + +void KGStreamerPlayer::seek (int val /*offset_in_deciseconds*/) { + //fprintf (stderr, "seek %d\n", val); + mutex.lock (); + if (gst_elm_play) + gst_element_seek (gst_elm_play, 1.0, GST_FORMAT_TIME, + (GstSeekFlags) (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), + GST_SEEK_TYPE_SET, val * GST_MSECOND * 100, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + mutex.unlock (); +} + +void KGStreamerPlayer::volume (int val) { + //fprintf (stderr, "position %d\n", val); + if (gst_elm_play) + g_object_set (G_OBJECT (gst_elm_play), "volume", 1.0*val/100, 0L); +} + +void KGStreamerPlayer::updatePosition () { + if (gst_elm_play) { + do { + GstMessage * msg = gst_bus_poll (gst_bus, (GstMessageType) (GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_DURATION), GST_MSECOND * 10); + if (!msg) + break; + gst_message_unref (msg); + } while (gst_bus); + + mutex.lock (); + if (gst_elm_play && callback) { + GstFormat fmt = GST_FORMAT_TIME; + gint64 val = 0; // usec + if (gst_element_query_position (gst_elm_play, &fmt, &val)) + callback->moviePosition (int (val / (GST_MSECOND * 100))); + } + mutex.unlock (); + QTimer::singleShot (500, this, SLOT (updatePosition ())); + } +} + +bool KGStreamerPlayer::event (QEvent * e) { + switch (e->type()) { + case event_finished: { + fprintf (stderr, "event_finished\n"); + mutex.lock (); + if (gst_elm_play) { + gst_bus_set_flushing (gst_bus, true); + if (gst_bus_sync) + g_signal_handler_disconnect (gst_bus, gst_bus_sync); + if (gst_bus_async) + g_signal_handler_disconnect (gst_bus, gst_bus_async); + gst_object_unref (gst_bus); + gst_object_unref (GST_OBJECT (gst_elm_play)); + gst_bus = 0L; + gst_elm_play = 0L; + color_balance = 0L; + gst_bus_sync = gst_bus_async = 0; + xoverlay = 0L; + } + mutex.unlock (); + if (callback) + callback->finished (); + else + QTimer::singleShot (0, this, SLOT (quit ())); + break; + } + //callback->movieParams (se->length/100, se->width, se->height, se->height ? 1.0*se->width/se->height : 1.0); + case event_size: { + GstSizeEvent * se = static_cast (e); + fprintf (stderr, "movie parms: %d %d %d\n", se->length, se->width, se->height); + if (callback) { + if (se->length < 0) se->length = 0; + callback->movieParams (se->length, se->width, se->height, se->height ? 1.0*se->width/se->height : 1.0, QStringList (), QStringList ()); + } + if (window_created && movie_width > 0 && movie_height > 0) { + XLockDisplay (display); + XResizeWindow (display, wid, movie_width, movie_height); + XFlush (display); + XUnlockDisplay (display); + } + // fall through + } + case event_playing: + notified_playing = true; + if (callback) + callback->playing (); + break; + case event_progress: + if (callback) + callback->loadingProgress + (static_cast (e)->progress); + break; + case event_eos: + case event_error: + stop (); + break; + case event_video: + if (callback) + callback->statusMessage ((int) KMPlayer::Callback::stat_hasvideo, QString ()); + break; + default: + return false; + } + return true; +} + +void KGStreamerPlayer::saveState (QSessionManager & sm) { + if (callback) + sm.setRestartHint (QSessionManager::RestartNever); +} + +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.format == 8 && + !strncmp(xevent.xclient.data.b, "quit_now", 8)) { + 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: + gstapp->lock (); + gstapp->stop (); + gstapp->unlock (); + break; + } + break; + } + case Expose: + if (!xevent.xexpose.count && xevent.xexpose.window == wid) { + mutex.lock (); + if (gst_elm_play) { + GstElement *videosink; + g_object_get (gst_elm_play, "video-sink", &videosink, NULL); + if (videosink && GST_IS_X_OVERLAY (videosink)) { + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (videosink), wid); + gst_x_overlay_expose (GST_X_OVERLAY (videosink)); + gst_object_unref (videosink); + } + } + mutex.unlock (); + } + break; + + case ConfigureNotify: + mutex.lock (); + if (xoverlay && GST_IS_X_OVERLAY (xoverlay)) + gst_x_overlay_expose (xoverlay); + 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) { + gstapp->lock (); + if (callback) + callback->toggleFullScreen (); + gstapp->unlock (); + } + prev_click_time = bev->time; + prev_click_x = bev->x; + prev_click_y = bev->y; + break; + } + default: + ; //if (xevent.type < LASTEvent) + // fprintf (stderr, "event %d\n", xevent.type); + } + } + } +}; + +int main(int argc, char **argv) { + if (!XInitThreads ()) { + fprintf (stderr, "XInitThreads () failed\n"); + return 1; + } + display = XOpenDisplay(NULL); + screen = XDefaultScreen(display); + + gst_init (NULL, NULL); + + gstapp = new KGStreamerPlayer (argc, argv); + + for(int i = 1; i < argc; i++) { + if (!strcmp (argv [i], "-ao")) { + ao_driver = argv [++i]; + } else if (!strcmp (argv [i], "-vo")) { + vo_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], "-wid") || !strcmp (argv [i], "-window-id")) { + 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], "-v")) { + verbose = true; + } else if (!strcmp (argv [i], "-c")) { + wants_config = true; + } else if (!strcmp (argv [i], "-f") && i < argc - 1) { + strncpy (configfile, argv [++i], sizeof (configfile)); + configfile[sizeof (configfile) - 1] = 0; + } else if (!strcmp (argv [i], "-loop") && i < argc - 1) { + repeat_count = atol (argv [++i]); + } else if (!strcmp (argv [i], "-cb")) { + 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 (!strncmp (argv [i], "-", 1)) { + fprintf (stderr, "usage: %s [-vo (xv|xshm)] [-ao