gstreamer/samples/VideoOverlay.cs
Stephan Sundermann df285b417a Samples: Ported overlay sample from 0.10
Hangs on shutdown when playing a video for some reason
2013-12-21 16:52:27 +01:00

274 lines
7.2 KiB
C#

// Authors
// Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
// Copyright (C) 2010 Andoni Morales <ylatuya@gmail.com>
// Copyright (C) 2013 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using System;
using System.Runtime.InteropServices;
using Gtk;
using Gst;
using Gst.Video;
using Gst.Base;
namespace Gstreameroverlay
{
public class MainWindow : Gtk.Window {
DrawingArea _da;
ulong _xWindowId;
Element _playbin;
HScale _scale;
Label _lbl;
bool _updatingScale;
bool _pipelineOK = false;
public static void Main (string[] args) {
if (System.Environment.OSVersion.Platform == PlatformID.Unix)
XInitThreads ();
Gtk.Application.Init ();
Gst.Application.Init ();
MainWindow window = new MainWindow ();
window.ShowAll ();
switch (System.Environment.OSVersion.Platform) {
case PlatformID.Unix:
window._xWindowId = gdk_x11_window_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;
}
Gtk.Application.Run ();
}
public MainWindow ()
: base ("Overlaytest") {
VBox vBox = new VBox ();
_da = new DrawingArea ();
_da.ModifyBg (Gtk.StateType.Normal, new Gdk.Color (0, 0, 0));
_da.SetSizeRequest (400, 300);
_da.DoubleBuffered = false;
vBox.PackStart (_da, false, false, 0);
_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 ();
if (_playbin != null) {
_playbin.SetState (Gst.State.Null);
_playbin.Dispose ();
_playbin = null;
}
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;
if (_playbin != null) {
_playbin.SetState (Gst.State.Null);
} else {
_playbin = ElementFactory.Make ("playbin", "playbin");
}
_scale.Value = 0;
if (_playbin == null)
Console.WriteLine ("Unable to create element 'playbin'");
_playbin.Bus.EnableSyncMessageEmission ();
_playbin.Bus.AddSignalWatch ();
_playbin.Bus.SyncMessage += delegate (object bus, SyncMessageArgs sargs) {
Gst.Message msg = sargs.Message;
if (!Gst.Video.GlobalVideo.IsVideoOverlayPrepareWindowHandleMessage (msg))
return;
Element src = msg.Src as Element;
if (src == null)
return;
try {
src["force-aspect-ratio"] = true;
}
catch (PropertyNotFoundException) {}
Element overlay = null;
if(src is Gst.Bin)
overlay = ((Gst.Bin) src).GetByInterface (VideoOverlayAdapter.GType);
VideoOverlayAdapter adapter = new VideoOverlayAdapter (overlay.Handle);
adapter.WindowHandle = _xWindowId;
adapter.HandleEvents (true);
};
_playbin.Bus.Message += delegate (object bus, MessageArgs margs) {
Message message = margs.Message;
switch (message.Type) {
case Gst.MessageType.Error:
GLib.GException 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;
}
};
switch (System.Environment.OSVersion.Platform) {
case PlatformID.Unix:
_playbin["uri"] = "file://" + dialog.Filename;
break;
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
_playbin["uri"] = "file:///" + dialog.Filename.Replace("\\","/");
break;
}
StateChangeReturn sret = _playbin.SetState (Gst.State.Playing);
if (sret == StateChangeReturn.Async) {
State state, pending;
sret = _playbin.GetState (out state, out pending, Constants.SECOND * 5L);
}
if (sret == StateChangeReturn.Success) {
Console.WriteLine ("State change successful");
_pipelineOK = true;
} else {
Console.WriteLine ("State change failed for {0} ({1})\n", dialog.Filename, sret);
}
}
dialog.Destroy ();
}
void ButtonPlayClicked (object sender, EventArgs args) {
if ( (_playbin != null) && _pipelineOK)
_playbin.SetState (Gst.State.Playing);
}
void ButtonPauseClicked (object sender, EventArgs args) {
if ( (_playbin != null) && _pipelineOK)
_playbin.SetState (Gst.State.Paused);
}
void ScaleValueChanged (object sender, EventArgs args) {
if (_updatingScale)
return;
long duration;
Gst.Format fmt = Gst.Format.Time;
Console.WriteLine ("Trying to seek");
if ( (_playbin != null) && _pipelineOK && _playbin.QueryDuration (fmt, out duration) && duration != -1) {
long pos = (long) (duration * _scale.Value);
Console.WriteLine ("Seek to {0}/{1} ({2}%)", pos, duration, _scale.Value);
bool ret = _playbin.SeekSimple (Format.Time, SeekFlags.Flush | SeekFlags.KeyUnit, pos);
Console.WriteLine ("Seeked {0}successfully", (ret ? "" : "not "));
}
}
bool UpdatePos () {
Gst.Format fmt = Gst.Format.Time;
long duration, pos;
pos = 0;
if ( (_playbin != null) && _pipelineOK &&
_playbin.QueryDuration (fmt, out duration) &&
_playbin.QueryPosition (fmt, out pos)) {
_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);
}
[DllImport ("libgdk-3.so.0") ]
static extern uint gdk_x11_window_get_xid (IntPtr handle);
[DllImport ("libgdk-win32-3.0-0.dll") ]
static extern IntPtr gdk_win32_drawable_get_handle (IntPtr handle);
[DllImport ("libX11.so.6")]
static extern int XInitThreads ();
}
}