|
|
|
/* This file is part of the KMPlayer application
|
|
|
|
Copyright (C) 2004 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 <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <config.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 "gstplayer.h"
|
|
|
|
#include <X11/X.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <gst/gst.h>
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
#include <gst/video/videooverlay.h>
|
|
|
|
#include <gst/video/colorbalance.h>
|
|
|
|
#else
|
|
|
|
#include <gst/interfaces/xoverlay.h>
|
|
|
|
#include <gst/interfaces/colorbalance.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static char configfile[2048];
|
|
|
|
|
|
|
|
static Display *display;
|
|
|
|
static KGStreamerPlayer *gstapp;
|
|
|
|
static KMPlayer::Callback_stub * callback;
|
|
|
|
static Window wid;
|
|
|
|
static TQMutex 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 = TQEvent::User;
|
|
|
|
static const int event_playing = TQEvent::User + 1;
|
|
|
|
static const int event_size = TQEvent::User + 2;
|
|
|
|
static const int event_eos = TQEvent::User + 3;
|
|
|
|
static const int event_progress = TQEvent::User + 4;
|
|
|
|
static const int event_error = TQEvent::User + 5;
|
|
|
|
static const int event_video = TQEvent::User + 6;
|
|
|
|
static TQString mrl;
|
|
|
|
static TQString 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;
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
static GstVideoOverlay *xoverlay;
|
|
|
|
#else
|
|
|
|
static GstXOverlay *xoverlay;
|
|
|
|
#endif
|
|
|
|
static GstColorBalance *color_balance;
|
|
|
|
static gulong gst_bus_sync;
|
|
|
|
static gulong gst_bus_async;
|
|
|
|
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" {
|
|
|
|
// 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);
|
|
|
|
TQApplication::postEvent (gstapp, new TQEvent ((TQEvent::Type)event_finished));
|
|
|
|
}
|
|
|
|
|
|
|
|
// NULL -> READY -> PAUSED -> PLAYING
|
|
|
|
|
|
|
|
static void
|
|
|
|
gstCapsSet (GstPad *pad,
|
|
|
|
GParamSpec * /*pspec*/,
|
|
|
|
gpointer /*data*/)
|
|
|
|
{
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
GstCaps *caps = gst_pad_get_current_caps (pad);
|
|
|
|
#else
|
|
|
|
GstCaps *caps = gst_pad_get_negotiated_caps (pad);
|
|
|
|
#endif
|
|
|
|
if (!caps)
|
|
|
|
return;
|
|
|
|
TQApplication::postEvent (gstapp, new TQEvent ((TQEvent::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);
|
|
|
|
}
|
|
|
|
TQApplication::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,
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
fmt,
|
|
|
|
#else
|
|
|
|
&fmt,
|
|
|
|
#endif
|
|
|
|
&len))
|
|
|
|
if (movie_length != len / (GST_MSECOND * 100)) {
|
|
|
|
movie_length = len / (GST_MSECOND * 100);
|
|
|
|
fprintf (stderr, "new length %d\n", movie_length);
|
|
|
|
TQApplication::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");
|
|
|
|
TQApplication::postEvent (gstapp, new TQEvent ((TQEvent::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 (
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
gst_message_get_structure(message),
|
|
|
|
#else
|
|
|
|
message->structure,
|
|
|
|
#endif
|
|
|
|
"buffer-percent", &percent);
|
|
|
|
TQApplication::postEvent (gstapp, new GstProgressEvent (percent));
|
|
|
|
//fprintf (stderr, "Buffering message (%u%%)\n", percent);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GST_MESSAGE_APPLICATION: {
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
const char * msg = gst_structure_get_name (gst_message_get_structure(message));
|
|
|
|
#else
|
|
|
|
const char * msg = gst_structure_get_name (message->structure);
|
|
|
|
#endif
|
|
|
|
fprintf (stderr, "app msg %s\n", msg ? msg : "<unknown>");
|
|
|
|
//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 ();
|
|
|
|
TQApplication::postEvent (gstapp, new TQEvent ((TQEvent::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
|
|
|
|
TQApplication::postEvent (gstapp,
|
|
|
|
new TQEvent ((TQEvent::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 (
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
gst_message_get_structure(msg),
|
|
|
|
#else
|
|
|
|
msg->structure,
|
|
|
|
#endif
|
|
|
|
"prepare-xwindow-id")) {
|
|
|
|
fprintf (stderr, "prepare-xwindow-id\n");
|
|
|
|
if (xoverlay) {
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
gst_video_overlay_set_window_handle (xoverlay, wid);
|
|
|
|
#else
|
|
|
|
gst_x_overlay_set_xwindow_id (xoverlay, wid);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
TQApplication::postEvent (gstapp, new TQEvent ((TQEvent::Type) event_error));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
GstSizeEvent::GstSizeEvent (int l, int w, int h)
|
|
|
|
: TQEvent ((TQEvent::Type) event_size),
|
|
|
|
length (l), width (w), height (h)
|
|
|
|
{}
|
|
|
|
|
|
|
|
GstProgressEvent::GstProgressEvent (const int p)
|
|
|
|
: TQEvent ((TQEvent::Type) event_progress), progress (p)
|
|
|
|
{}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
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) {
|
|
|
|
gstapp->play (repeat);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::stop () {
|
|
|
|
TQTimer::singleShot (0, gstapp, TQT_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, TQString) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void Backend::setSubtitle (int, TQString) {
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ());
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
err = TQString ("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)
|
|
|
|
: TQApplication (_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 (TQByteArray & buf) {
|
|
|
|
TQDomDocument doc;
|
|
|
|
TQDomElement root = doc.createElement (TQString ("document"));
|
|
|
|
doc.appendChild (root);
|
|
|
|
TQCString 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() ? "<empty>" : 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),
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
GST_TYPE_VIDEO_OVERLAY
|
|
|
|
#else
|
|
|
|
GST_TYPE_X_OVERLAY
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
else
|
|
|
|
element = videosink;
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
if (GST_IS_VIDEO_OVERLAY (element)) {
|
|
|
|
xoverlay = GST_VIDEO_OVERLAY (element);
|
|
|
|
gst_video_overlay_set_window_handle (xoverlay, wid);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (GST_IS_X_OVERLAY (element)) {
|
|
|
|
xoverlay = GST_X_OVERLAY (element);
|
|
|
|
gst_x_overlay_set_xwindow_id (xoverlay, wid);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
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);
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
gst_bus_set_sync_handler (gst_bus, gst_bus_sync_signal_handler, 0L, 0L);
|
|
|
|
#else
|
|
|
|
gst_bus_set_sync_handler (gst_bus, gst_bus_sync_signal_handler, 0L);
|
|
|
|
#endif
|
|
|
|
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 (TQChar ('/')))
|
|
|
|
mrl = TQString ("file://") + mrl;
|
|
|
|
uri = g_strdup (mrl.local8Bit ());
|
|
|
|
g_object_set (gst_elm_play, "uri", uri, NULL);
|
|
|
|
if (!sub_mrl.isEmpty ()) {
|
|
|
|
if (sub_mrl.startsWith (TQChar ('/')))
|
|
|
|
sub_mrl = TQString ("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);
|
|
|
|
TQTimer::singleShot (500, this, TQT_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 ();
|
|
|
|
TQApplication::postEvent (gstapp, new TQEvent ((TQEvent::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 () ? "<empty>" : 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))
|
|
|
|
TQApplication::postEvent (gstapp, new TQEvent ((TQEvent::Type) event_finished));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KGStreamerPlayer::finished () {
|
|
|
|
TQTimer::singleShot (10, this, TQT_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, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
fmt,
|
|
|
|
#else
|
|
|
|
&fmt,
|
|
|
|
#endif
|
|
|
|
&val))
|
|
|
|
callback->moviePosition (int (val / (GST_MSECOND * 100)));
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
TQTimer::singleShot (500, this, TQT_SLOT (updatePosition ()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KGStreamerPlayer::event (TQEvent * 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
|
|
|
|
TQTimer::singleShot (0, this, TQT_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 <GstSizeEvent *> (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, TQStringList (), TQStringList ());
|
|
|
|
}
|
|
|
|
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 <GstProgressEvent *> (e)->progress);
|
|
|
|
break;
|
|
|
|
case event_eos:
|
|
|
|
case event_error:
|
|
|
|
stop ();
|
|
|
|
break;
|
|
|
|
case event_video:
|
|
|
|
if (callback)
|
|
|
|
callback->statusMessage ((int) KMPlayer::Callback::stat_hasvideo, TQString ());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KGStreamerPlayer::saveState (TQSessionManager & sm) {
|
|
|
|
if (callback)
|
|
|
|
sm.setRestartHint (TQSessionManager::RestartNever);
|
|
|
|
}
|
|
|
|
|
|
|
|
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.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 GST_CHECK_VERSION(1,0,0)
|
|
|
|
if (videosink && GST_IS_VIDEO_OVERLAY (videosink)) {
|
|
|
|
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (videosink), wid);
|
|
|
|
gst_video_overlay_expose (GST_VIDEO_OVERLAY (videosink));
|
|
|
|
gst_object_unref (videosink);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
mutex.unlock ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ConfigureNotify:
|
|
|
|
mutex.lock ();
|
|
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
|
|
if (xoverlay && GST_IS_VIDEO_OVERLAY (xoverlay)) {
|
|
|
|
gst_video_overlay_expose (xoverlay);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (xoverlay && GST_IS_X_OVERLAY (xoverlay)) {
|
|
|
|
gst_x_overlay_expose (xoverlay);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
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")) {
|
|
|
|
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 (!strncmp (argv [i], "-", 1)) {
|
|
|
|
fprintf (stderr, "usage: %s [-vo (xv|xshm)] [-ao <audio driver>] [-f <config file>] [-dvd-device <device>] [-vcd-device <device>] [-v] [(-wid|-window-id) <window>] [(-root|-window)] [-cb <DCOP callback name> [-c]] [<url>]\n", argv[0]);
|
|
|
|
delete gstapp;
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
mrl = TQString::fromLocal8Bit (argv[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DCOPClient dcopclient;
|
|
|
|
dcopclient.registerAs ("kgstreamerplayer");
|
|
|
|
Backend * backend = new Backend;
|
|
|
|
|
|
|
|
XEventThread * eventThread = new XEventThread;
|
|
|
|
eventThread->start ();
|
|
|
|
|
|
|
|
gstapp->init ();
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
TQByteArray buf;
|
|
|
|
if (wants_config)
|
|
|
|
getConfigEntries (buf);
|
|
|
|
callback->started (dcopclient.appId (), buf);
|
|
|
|
} else
|
|
|
|
TQTimer::singleShot (10, gstapp, TQT_SLOT (play (int)));
|
|
|
|
|
|
|
|
gstapp->exec ();
|
|
|
|
|
|
|
|
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 = XInternAtom (display, "XVIDEO", false);
|
|
|
|
ev.xclient.format = 8;
|
|
|
|
strcpy(ev.xclient.data.b, "quit_now");
|
|
|
|
XSendEvent (display, wid, false, StructureNotifyMask, &ev);
|
|
|
|
XFlush (display);
|
|
|
|
XUnlockDisplay(display);
|
|
|
|
eventThread->wait (500);
|
|
|
|
delete eventThread;
|
|
|
|
|
|
|
|
gstapp->stop ();
|
|
|
|
delete backend;
|
|
|
|
delete gstapp;
|
|
|
|
|
|
|
|
fprintf (stderr, "closing display\n");
|
|
|
|
XCloseDisplay (display);
|
|
|
|
fprintf (stderr, "done\n");
|
|
|
|
fflush (stderr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "gstplayer.moc"
|