diff --git a/gstreamer-sharp/baseplugins/XvImageSink.cs b/gstreamer-sharp/baseplugins/XvImageSink.cs new file mode 100644 index 0000000000..adf391c8ae --- /dev/null +++ b/gstreamer-sharp/baseplugins/XvImageSink.cs @@ -0,0 +1,54 @@ +using System; +using System.Runtime.InteropServices; +using Gst; +using Gst.Interfaces; + +namespace Gst.BasePlugins { + [GTypeName ("GstXvImageSink") ] + public class XvImageSink : Element, XOverlay { + public XvImageSink (IntPtr raw) : base (raw) { } + + public static XvImageSink Make (string name) { + return ElementFactory.Make ("xvimagesink", name) as XvImageSink; + } + + [DllImport ("gstinterfaces-0.10.dll") ] + static extern void gst_x_overlay_expose (IntPtr raw); + + public void Expose() { + gst_x_overlay_expose (Handle); + } + + [DllImport ("gstinterfaces-0.10.dll") ] + static extern void gst_x_overlay_handle_events (IntPtr raw, bool handle_events); + + public void HandleEvents (bool handle_events) { + gst_x_overlay_handle_events (Handle, handle_events); + } + + [DllImport ("gstinterfaces-0.10.dll") ] + static extern void gst_x_overlay_got_xwindow_id (IntPtr raw, UIntPtr xwindow_id); + + public void GotXwindowId (ulong xwindow_id) { + gst_x_overlay_got_xwindow_id (Handle, new UIntPtr (xwindow_id)); + } + + [DllImport ("gstinterfaces-0.10.dll") ] + static extern void gst_x_overlay_prepare_xwindow_id (IntPtr raw); + + public void PrepareXwindowId() { + gst_x_overlay_prepare_xwindow_id (Handle); + } + + [DllImport ("gstinterfaces-0.10.dll") ] + static extern void gst_x_overlay_set_xwindow_id (IntPtr raw, UIntPtr xwindow_id); + + public ulong XwindowId { + set { + gst_x_overlay_set_xwindow_id (Handle, new UIntPtr (value)); + } + } + + } +} + diff --git a/samples/GtkVideoPlayer.cs b/samples/GtkVideoPlayer.cs new file mode 100644 index 0000000000..6e2fb7f5fe --- /dev/null +++ b/samples/GtkVideoPlayer.cs @@ -0,0 +1,188 @@ +// Authors +// Copyright (C) 2008 Paul Burton +using System; +using System.Runtime.InteropServices; + +using Gtk; +using Gst; +using Gst.Interfaces; +using Gst.BasePlugins; + +public class MainWindow : Gtk.Window { + DrawingArea _da; + Pipeline _pipeline; + HScale _scale; + Label _lbl; + bool _updatingScale; + bool _pipelineOK; + + public static void Main (string[] args) { + Gtk.Application.Init (); + Gst.Application.Init (); + MainWindow window = new MainWindow (); + window.ShowAll (); + 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); + 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 (); + 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 (_pipeline != null) { + _pipeline.SetState (Gst.State.Null); + _pipeline.Dispose (); + } + + _scale.Value = 0; + + _pipeline = new Pipeline (string.Empty); + + Element playbin = ElementFactory.Make ("playbin", "playbin"); + XvImageSink sink = XvImageSink.Make ("sink"); + + if (_pipeline == null) + Console.WriteLine ("Unable to create pipeline"); + if (playbin == null) + Console.WriteLine ("Unable to create element 'playbin'"); + if (sink == null) + Console.WriteLine ("Unable to create element 'sink'"); + + _pipeline.Add (playbin); + + sink.XwindowId = gdk_x11_drawable_get_xid (_da.GdkWindow.Handle); + + playbin["video-sink"] = sink; + playbin["uri"] = "file://" + dialog.Filename; + + StateChangeReturn sret = _pipeline.SetState (Gst.State.Playing); + + if (sret == StateChangeReturn.Async) { + State state, pending; + sret = _pipeline.GetState (out state, out pending, Clock.Second * 5); + } + + if (sret == StateChangeReturn.Success) + _pipelineOK = true; + else + Console.WriteLine ("State change failed for {0} ({1})\n", dialog.Filename, sret); + } + + dialog.Destroy (); + } + + void ButtonPlayClicked (object sender, EventArgs args) { + if ( (_pipeline != null) && _pipelineOK) + _pipeline.SetState (Gst.State.Playing); + } + + void ButtonPauseClicked (object sender, EventArgs args) { + if ( (_pipeline != null) && _pipelineOK) + _pipeline.SetState (Gst.State.Paused); + } + + void ScaleValueChanged (object sender, EventArgs args) { + if (_updatingScale) + return; + + long duration; + Gst.Format fmt = Gst.Format.Time; + + if ( (_pipeline != null) && _pipelineOK && _pipeline.QueryDuration (ref fmt, out duration)) { + long pos = (long) (duration * _scale.Value); + //Console.WriteLine ("Seek to {0}/{1} ({2}%)", pos, duration, _scale.Value); + + _pipeline.Seek (Format.Time, SeekFlags.Flush, pos); + } + } + + bool UpdatePos () { + Gst.Format fmt = Gst.Format.Time; + long duration, pos; + if ( (_pipeline != null) && _pipelineOK && + _pipeline.QueryDuration (ref fmt, out duration) && + _pipeline.QueryPosition (ref 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-x11-2.0") ] + static extern uint gdk_x11_drawable_get_xid (IntPtr handle); +} diff --git a/samples/Makefile.am b/samples/Makefile.am index a0b77895fb..cf01618cd9 100644 --- a/samples/Makefile.am +++ b/samples/Makefile.am @@ -1,4 +1,4 @@ -TARGETS = playbin-player.exe decodebin-transcoder.exe helloworld.exe typefind.exe +TARGETS = playbin-player.exe decodebin-transcoder.exe helloworld.exe typefind.exe metadata.exe gtk-video-player.exe DEBUGS = $(addsuffix .mdb, $(TARGETS)) all: $(TARGETS) link @@ -28,6 +28,9 @@ metadata.exe: $(srcdir)/MetaData.cs $(assemblies) mp3launchparse.exe: $(srcdir)/MP3LaunchParse.cs $(assemblies) $(CSC) -out:$@ $(GLIBSHARP_LIBS) $(references) $(srcdir)/MP3LaunchParse.cs +gtk-video-player.exe: $(srcdir)/GtkVideoPlayer.cs $(assemblies) + $(CSC) $(GLIBSHARP_LIBS) $(references) -pkg:gtk-sharp-2.0 $(srcdir)/GtkVideoPlayer.cs /out:gtk-video-player.exe + link: ln -sf $(top_builddir)/gstreamer-sharp/gstreamer-sharp.dll gstreamer-sharp.dll ln -sf $(top_builddir)/gstreamer-sharp/gstreamer-sharp.dll.config gstreamer-sharp.dll.config diff --git a/samples/MetaData.cs b/samples/MetaData.cs index eb28cffc0c..4c92029be0 100644 --- a/samples/MetaData.cs +++ b/samples/MetaData.cs @@ -1,161 +1,167 @@ -// // Authors -// Khaled Mohammed (khaled.mohammed@gmail.com) -// -// (C) 2006 -// +// Copyright (C) 2006 Khaled Mohammed +// Copyright (C) 2008 Paul Burton + +using System; +using System.IO; using Gst; -using System; -public class MetaData -{ +public class MetaData { + static Element pipeline = null; + static Element source = null; - static Element pipeline = null; - static Element source = null; + static void PrintTag (TagList list, string tag) { + uint count = list.GetTagSize (tag); - static void PrintTag( TagList list, string tag) { - uint count = list.GetTagSize(tag); - Console.WriteLine("Tags found = " + count); - for(uint i =0; i < count; i++) - { - string str; - if(Tag.GetGType(tag) == GLib.GType.String) { - if(!list.GetStringIndex(tag, i, out str)) - Console.Error.WriteLine("g_assert_not_reached()???"); - } else { - str = (String) list.GetValueIndex(tag, i).Val; - } + //Console.WriteLine ("Tags found = " + count); - if(i == 0) - Console.WriteLine("{0}:\t {1}", Tag.GetNick(tag), str); - else - Console.WriteLine("\t{0}", str); - } - } + for (uint i = 0; i < count; i++) { + string str; - static bool MessageLoop(Element element, ref TagList tags) - { - Bus bus = element.Bus; - bool done = false; + try { + str = list[tag, i].ToString (); + } catch (Exception ex) { + str = ex.Message; + } - while(!done) { - Message message = bus.Pop(); - if(message == null) - break; + if (i == 0) + Console.WriteLine ("{0}: {1}", Tag.GetNick (tag).PadRight (25), str); + else + Console.WriteLine ("{0}{1}", string.Empty.PadRight (27), str); + } + } - switch(message.Type) { - case MessageType.Error: - string error; - message.ParseError(out error); - message.Dispose(); - return true; - case MessageType.Eos: - message.Dispose(); - return true; - case MessageType.Tag: { - TagList new_tags = new TagList(); - message.ParseTag(new_tags); - if(tags != null) { - tags = tags.Merge(new_tags, TagMergeMode.KeepAll); - } - else { - tags = new_tags; - } - //tags.Foreach(PrintTag); - //new_tags.Dispose(); - break; - } - default: - break; - } - message.Dispose(); - } - bus.Dispose(); - return true; - } + static bool MessageLoop (Element element, ref TagList tags) { + Bus bus = element.Bus; + bool done = false; - static void MakePipeline() - { - Element decodebin; + while (!done) { + Message message = bus.Pop (); - if(pipeline != null) { - pipeline.Dispose(); - } - - pipeline = new Pipeline(String.Empty); - source = ElementFactory.Make("filesrc", "source"); - decodebin = ElementFactory.Make("decodebin", "decodebin"); + if (message == null) + break; - if(pipeline == null) Console.Error.WriteLine("Pipeline count not be created"); - if(source == null) Console.Error.WriteLine("Element filesrc could not be created"); - if(decodebin == null) Console.Error.WriteLine("Element decodebin coult not be created"); + switch (message.Type) { + case MessageType.Error: + Enum error; + string msg; + message.ParseError (out error, out msg); + message.Dispose (); + return true; - Bin bin = (Bin) pipeline; - bin.AddMany(source, decodebin); - if(!source.Link(decodebin)) - Console.Error.WriteLine("filesrc could not be linked with decodebin"); - decodebin.Dispose(); - } + case MessageType.Eos: + message.Dispose (); + return true; - public static void Main(string [] args) - { - Application.Init(); + case MessageType.Tag: + TagList new_tags; - if(args.Length < 1) - { - Console.Error.WriteLine("Please give filenames to read metadata from\n\n"); - return; - } + message.ParseTag (out new_tags); - MakePipeline(); + if (tags != null) { + tags = tags.Merge (new_tags, TagMergeMode.KeepAll); + new_tags.Dispose (); + } else + tags = new_tags; - int i=-1; - while(++i < args.Length) - { - State state, pending; - TagList tags = null; + break; - string filename = args[i]; - source.SetProperty("location", filename); + default: + break; + } - StateChangeReturn sret = pipeline.SetState(State.Paused); + message.Dispose (); + } - if(sret == StateChangeReturn.Async) { - if(StateChangeReturn.Success != pipeline.GetState(out state, out pending, Clock.Second * 5)) { - Console.Error.WriteLine("State change failed for {0}. Aborting\n", filename); - break; - } - } else if(sret != StateChangeReturn.Success) { - Console.Error.WriteLine("{0} - Could not read file\n", filename); - continue; - } + bus.Dispose (); + return true; + } - if(!MessageLoop(pipeline, ref tags)) { - Console.Error.WriteLine("Failed in message reading for {0}", args[i]); - } + static void MakePipeline () { + Element decodebin; - if(tags != null) { - Console.WriteLine("Metadata for {0}:", args[i]); - tags.Foreach(new TagForeachFunc(PrintTag)); - tags.Dispose(); - tags = null; - } else Console.Error.WriteLine("No metadata found for {0}", args[0]); + if (pipeline != null) + pipeline.Dispose (); - sret = pipeline.SetState(State.Null); + pipeline = new Pipeline (String.Empty); + source = ElementFactory.Make ("filesrc", "source"); + decodebin = ElementFactory.Make ("decodebin", "decodebin"); - if(StateChangeReturn.Async == sret) { - if(StateChangeReturn.Failure == pipeline.GetState(out state, out pending, Clock.TimeNone)) { - Console.Error.WriteLine("State change failed. Aborting"); - } - } - } + if (pipeline == null) + Console.WriteLine ("Pipeline could not be created"); + if (source == null) + Console.WriteLine ("Element filesrc could not be created"); + if (decodebin == null) + Console.WriteLine ("Element decodebin could not be created"); - if(pipeline != null) - { - pipeline.Dispose(); - } + Bin bin = (Bin) pipeline; + bin.Add (source, decodebin); - } + if (!source.Link (decodebin)) + Console.WriteLine ("filesrc could not be linked with decodebin"); + + //decodebin.Dispose (); + } + + public static void Main (string [] args) { + Application.Init (); + + if (args.Length < 1) { + Console.WriteLine ("Please give filenames to read metadata from\n\n"); + return; + } + + MakePipeline (); + + int i = -1; + while (++i < args.Length) { + State state, pending; + TagList tags = null; + + string filename = args[i]; + + if (!File.Exists (filename)) { + Console.WriteLine ("File {0} does not exist", filename); + continue; + } + + source["location"] = filename; + + StateChangeReturn sret = pipeline.SetState (State.Paused); + + if (sret == StateChangeReturn.Async) { + if (StateChangeReturn.Success != pipeline.GetState (out state, out pending, Clock.Second * 5)) { + Console.WriteLine ("State change failed for {0}. Aborting\n", filename); + break; + } + } else if (sret != StateChangeReturn.Success) { + Console.WriteLine ("{0} - Could not read file ({1})\n", filename, sret); + continue; + } + + if (!MessageLoop (pipeline, ref tags)) + Console.Error.WriteLine ("Failed in message reading for {0}", args[i]); + + if (tags != null) { + Console.WriteLine ("Metadata for {0}:", filename); + + foreach (string tag in tags.Tags) + PrintTag (tags, tag); + tags.Dispose (); + tags = null; + } else + Console.WriteLine ("No metadata found for {0}", args[0]); + + sret = pipeline.SetState (State.Null); + + if (StateChangeReturn.Async == sret) { + if (StateChangeReturn.Failure == pipeline.GetState (out state, out pending, Clock.TimeNone)) + Console.WriteLine ("State change failed. Aborting"); + } + } + + if (pipeline != null) + pipeline.Dispose (); + } } -