2009-05-21 18:57:26 +00:00
|
|
|
// Authors
|
|
|
|
// Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
|
|
|
|
using System;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
|
using Gtk;
|
|
|
|
using Gst;
|
|
|
|
using Gst.Interfaces;
|
|
|
|
using Gst.BasePlugins;
|
|
|
|
|
|
|
|
public class MainWindow : Gtk.Window {
|
|
|
|
DrawingArea _da;
|
2009-10-02 09:53:09 +00:00
|
|
|
ulong _xWindowId;
|
|
|
|
PlayBin2 _playbin;
|
2009-05-21 18:57:26 +00:00
|
|
|
HScale _scale;
|
|
|
|
Label _lbl;
|
|
|
|
bool _updatingScale;
|
2009-10-03 08:14:44 +00:00
|
|
|
bool _pipelineOK = false;
|
2009-05-21 18:57:26 +00:00
|
|
|
|
|
|
|
public static void Main (string[] args) {
|
|
|
|
Gtk.Application.Init ();
|
|
|
|
Gst.Application.Init ();
|
|
|
|
MainWindow window = new MainWindow ();
|
|
|
|
window.ShowAll ();
|
2009-10-02 09:53:09 +00:00
|
|
|
|
2009-11-25 07:16:05 +00:00
|
|
|
#if HAVE_GTK_2_17_3
|
|
|
|
if (!gdk_window_ensure_native (window._da.GdkWindow.Handle)) {
|
|
|
|
Console.WriteLine ("Can't ensure a native window for the drawing area");
|
|
|
|
}
|
|
|
|
#endif
|
2009-10-02 09:53:09 +00:00
|
|
|
switch (System.Environment.OSVersion.Platform) {
|
|
|
|
case PlatformID.Unix:
|
|
|
|
window._xWindowId = gdk_x11_drawable_get_xid (window._da.GdkWindow.Handle);
|
|
|
|
break;
|
|
|
|
case PlatformID.Win32NT:
|
|
|
|
case PlatformID.Win32S:
|
|
|
|
case PlatformID.Win32Windows:
|
|
|
|
case PlatformID.WinCE:
|
|
|
|
window._xWindowId = (ulong) gdk_win32_drawable_get_handle (window._da.GdkWindow.Handle);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-05-21 18:57:26 +00:00
|
|
|
Gtk.Application.Run ();
|
|
|
|
}
|
|
|
|
|
|
|
|
public MainWindow ()
|
|
|
|
: base (WindowType.Toplevel) {
|
|
|
|
VBox vBox = new VBox ();
|
|
|
|
|
|
|
|
_da = new DrawingArea ();
|
|
|
|
_da.ModifyBg (Gtk.StateType.Normal, new Gdk.Color (0, 0, 0));
|
|
|
|
_da.SetSizeRequest (400, 300);
|
2009-10-02 09:53:09 +00:00
|
|
|
_da.DoubleBuffered = false;
|
2009-05-21 18:57:26 +00:00
|
|
|
vBox.PackStart (_da);
|
|
|
|
|
|
|
|
_scale = new HScale (0, 1, 0.01);
|
|
|
|
_scale.DrawValue = false;
|
|
|
|
_scale.ValueChanged += ScaleValueChanged;
|
|
|
|
vBox.PackStart (_scale, false, false, 0);
|
|
|
|
|
|
|
|
HBox hBox = new HBox ();
|
|
|
|
|
|
|
|
Button btnOpen = new Button ();
|
|
|
|
btnOpen.Label = "Open";
|
|
|
|
btnOpen.Clicked += ButtonOpenClicked;
|
|
|
|
|
|
|
|
hBox.PackStart (btnOpen, false, false, 0);
|
|
|
|
|
|
|
|
Button btnPlay = new Button ();
|
|
|
|
btnPlay.Label = "Play";
|
|
|
|
btnPlay.Clicked += ButtonPlayClicked;
|
|
|
|
|
|
|
|
hBox.PackStart (btnPlay, false, false, 0);
|
|
|
|
|
|
|
|
Button btnPause = new Button ();
|
|
|
|
btnPause.Label = "Pause";
|
|
|
|
btnPause.Clicked += ButtonPauseClicked;
|
|
|
|
|
|
|
|
hBox.PackStart (btnPause, false, false, 0);
|
|
|
|
|
|
|
|
_lbl = new Label ();
|
|
|
|
_lbl.Text = "00:00 / 00:00";
|
|
|
|
|
|
|
|
hBox.PackEnd (_lbl, false, false, 0);
|
|
|
|
|
|
|
|
vBox.PackStart (hBox, false, false, 3);
|
|
|
|
|
|
|
|
Add (vBox);
|
|
|
|
|
|
|
|
WindowPosition = Gtk.WindowPosition.Center;
|
|
|
|
DeleteEvent += OnDeleteEvent;
|
|
|
|
|
|
|
|
GLib.Timeout.Add (1000, new GLib.TimeoutHandler (UpdatePos));
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnDeleteEvent (object sender, DeleteEventArgs args) {
|
|
|
|
Gtk.Application.Quit ();
|
2009-10-02 09:53:09 +00:00
|
|
|
|
|
|
|
if (_playbin != null) {
|
|
|
|
_playbin.SetState (Gst.State.Null);
|
|
|
|
_playbin.Dispose ();
|
|
|
|
_playbin = null;
|
|
|
|
}
|
|
|
|
|
2009-05-21 18:57:26 +00:00
|
|
|
args.RetVal = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ButtonOpenClicked (object sender, EventArgs args) {
|
|
|
|
FileChooserDialog dialog = new FileChooserDialog ("Open", this, FileChooserAction.Open, new object[] { "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept });
|
|
|
|
dialog.SetCurrentFolder (Environment.GetFolderPath (Environment.SpecialFolder.Personal));
|
|
|
|
|
|
|
|
if (dialog.Run () == (int) ResponseType.Accept) {
|
|
|
|
_pipelineOK = false;
|
|
|
|
|
2009-10-02 09:53:09 +00:00
|
|
|
if (_playbin != null) {
|
|
|
|
_playbin.SetState (Gst.State.Null);
|
|
|
|
} else {
|
|
|
|
_playbin = new PlayBin2 ();
|
2009-05-21 18:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_scale.Value = 0;
|
|
|
|
|
2009-10-02 09:53:09 +00:00
|
|
|
if (_playbin == null)
|
|
|
|
Console.WriteLine ("Unable to create element 'playbin'");
|
2009-05-21 18:57:26 +00:00
|
|
|
|
2009-10-02 09:53:09 +00:00
|
|
|
_playbin.Bus.EnableSyncMessageEmission ();
|
|
|
|
_playbin.Bus.AddSignalWatch ();
|
2009-05-21 18:57:26 +00:00
|
|
|
|
2009-10-02 09:53:09 +00:00
|
|
|
_playbin.Bus.SyncMessage += delegate (object bus, SyncMessageArgs sargs) {
|
|
|
|
Gst.Message msg = sargs.Message;
|
|
|
|
if (msg == null || msg.Type != Gst.MessageType.Element ||
|
|
|
|
msg.Structure == null || msg.Structure.Name == null ||
|
|
|
|
!msg.Structure.Name.Equals ("prepare-xwindow-id"))
|
|
|
|
return;
|
|
|
|
|
2009-10-03 08:14:44 +00:00
|
|
|
Element src = msg.Src as Element;
|
|
|
|
if (src == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (src.HasProperty ("force-aspect-ratio"))
|
|
|
|
src["force-aspect-ratio"] = true;
|
|
|
|
|
|
|
|
(src as XOverlay).XwindowId = _xWindowId;
|
|
|
|
(src as XOverlay).HandleEvents (true);
|
2009-10-02 09:53:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
_playbin.Bus.Message += delegate (object bus, MessageArgs margs) {
|
|
|
|
Message message = margs.Message;
|
|
|
|
|
|
|
|
switch (message.Type) {
|
|
|
|
case Gst.MessageType.Error:
|
|
|
|
Enum err;
|
|
|
|
string msg;
|
|
|
|
|
|
|
|
message.ParseError (out err, out msg);
|
|
|
|
Console.WriteLine (String.Format ("Error message: {0}", msg));
|
|
|
|
_pipelineOK = false;
|
|
|
|
break;
|
|
|
|
case Gst.MessageType.Eos:
|
|
|
|
Console.WriteLine ("EOS");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
2009-05-21 18:57:26 +00:00
|
|
|
|
2009-10-02 09:53:09 +00:00
|
|
|
_playbin["uri"] = "file://" + dialog.Filename;
|
2009-05-21 18:57:26 +00:00
|
|
|
|
2009-10-02 09:53:09 +00:00
|
|
|
StateChangeReturn sret = _playbin.SetState (Gst.State.Playing);
|
2009-05-21 18:57:26 +00:00
|
|
|
|
|
|
|
if (sret == StateChangeReturn.Async) {
|
|
|
|
State state, pending;
|
2009-10-02 09:53:09 +00:00
|
|
|
sret = _playbin.GetState (out state, out pending, Clock.Second * 5);
|
2009-05-21 18:57:26 +00:00
|
|
|
}
|
|
|
|
|
2009-10-03 08:14:44 +00:00
|
|
|
if (sret == StateChangeReturn.Success) {
|
|
|
|
Console.WriteLine ("State change successful");
|
2009-05-21 18:57:26 +00:00
|
|
|
_pipelineOK = true;
|
2009-10-03 08:14:44 +00:00
|
|
|
} else {
|
2009-05-21 18:57:26 +00:00
|
|
|
Console.WriteLine ("State change failed for {0} ({1})\n", dialog.Filename, sret);
|
2009-10-03 08:14:44 +00:00
|
|
|
}
|
2009-05-21 18:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dialog.Destroy ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ButtonPlayClicked (object sender, EventArgs args) {
|
2009-10-02 09:53:09 +00:00
|
|
|
if ( (_playbin != null) && _pipelineOK)
|
|
|
|
_playbin.SetState (Gst.State.Playing);
|
2009-05-21 18:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ButtonPauseClicked (object sender, EventArgs args) {
|
2009-10-02 09:53:09 +00:00
|
|
|
if ( (_playbin != null) && _pipelineOK)
|
|
|
|
_playbin.SetState (Gst.State.Paused);
|
2009-05-21 18:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScaleValueChanged (object sender, EventArgs args) {
|
|
|
|
if (_updatingScale)
|
|
|
|
return;
|
|
|
|
|
|
|
|
long duration;
|
|
|
|
Gst.Format fmt = Gst.Format.Time;
|
2009-10-03 08:14:44 +00:00
|
|
|
Console.WriteLine ("Trying to seek");
|
2009-05-21 18:57:26 +00:00
|
|
|
|
2009-10-02 09:53:09 +00:00
|
|
|
if ( (_playbin != null) && _pipelineOK && _playbin.QueryDuration (ref fmt, out duration) && duration != -1) {
|
2009-05-21 18:57:26 +00:00
|
|
|
long pos = (long) (duration * _scale.Value);
|
2009-10-02 09:53:09 +00:00
|
|
|
Console.WriteLine ("Seek to {0}/{1} ({2}%)", pos, duration, _scale.Value);
|
2009-05-21 18:57:26 +00:00
|
|
|
|
2009-10-03 08:14:44 +00:00
|
|
|
bool ret = _playbin.Seek (Format.Time, SeekFlags.Flush | SeekFlags.KeyUnit, pos);
|
|
|
|
|
|
|
|
Console.WriteLine ("Seeked {0}successfully", (ret ? "" : "not "));
|
2009-05-21 18:57:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UpdatePos () {
|
|
|
|
Gst.Format fmt = Gst.Format.Time;
|
|
|
|
long duration, pos;
|
2009-10-02 09:53:09 +00:00
|
|
|
if ( (_playbin != null) && _pipelineOK &&
|
|
|
|
_playbin.QueryDuration (ref fmt, out duration) &&
|
|
|
|
_playbin.QueryPosition (ref fmt, out pos)) {
|
2009-05-21 18:57:26 +00:00
|
|
|
_lbl.Text = string.Format ("{0} / {1}", TimeString (pos), TimeString (duration));
|
|
|
|
|
|
|
|
_updatingScale = true;
|
|
|
|
_scale.Value = (double) pos / duration;
|
|
|
|
_updatingScale = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
string TimeString (long t) {
|
|
|
|
long secs = t / 1000000000;
|
|
|
|
int mins = (int) (secs / 60);
|
|
|
|
secs = secs - (mins * 60);
|
|
|
|
|
|
|
|
if (mins >= 60) {
|
|
|
|
int hours = (int) (mins / 60);
|
|
|
|
mins = mins - (hours * 60);
|
|
|
|
|
|
|
|
return string.Format ("{0}:{1:d2}:{2:d2}", hours, mins, secs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return string.Format ("{0}:{1:d2}", mins, secs);
|
|
|
|
}
|
|
|
|
|
2009-08-14 06:37:09 +00:00
|
|
|
[DllImport ("libgdk-x11-2.0.so.0") ]
|
2009-05-21 18:57:26 +00:00
|
|
|
static extern uint gdk_x11_drawable_get_xid (IntPtr handle);
|
2009-08-14 06:37:09 +00:00
|
|
|
|
|
|
|
[DllImport ("libgdk-win32-2.0-0.dll") ]
|
|
|
|
static extern IntPtr gdk_win32_drawable_get_handle (IntPtr handle);
|
2009-11-25 07:16:05 +00:00
|
|
|
|
|
|
|
#if HAVE_GTK_2_17_3
|
|
|
|
[DllImport ("libgdk-win32-2.0-0.dll") ]
|
|
|
|
static extern bool gdk_window_ensure_native (IntPtr handle);
|
|
|
|
#endif
|
2009-05-21 18:57:26 +00:00
|
|
|
}
|