This commit is contained in:
Akkariin Meiko
2022-03-12 03:16:09 +08:00
Unverified
parent 12b76e0c7a
commit 27c4ec74a1
10075 changed files with 5122287 additions and 1 deletions
@@ -0,0 +1,30 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
namespace GstreamerSharp
{
class Playback
{
public static void Main (string[] args)
{
// Initialize Gstreamer
Application.Init(ref args);
// Build the pipeline
var pipeline = Parse.Launch("playbin uri=http://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4");
// Start playing
pipeline.SetState(State.Playing);
// Wait until error or EOS
var bus = pipeline.Bus;
var msg = bus.TimedPopFiltered (Constants.CLOCK_TIME_NONE, MessageType.Eos | MessageType.Error);
// Free resources
pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,91 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
static bool IsLive;
static Element Pipeline;
static GLib.MainLoop MainLoop;
public static void Main (string[] args)
{
// Initialize GStreamer
Application.Init (ref args);
// Build the pipeline
Pipeline = Parse.Launch ("playbin uri=http://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4");
var bus = Pipeline.Bus;
// Start playing
var ret = Pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
} else if (ret == StateChangeReturn.NoPreroll) {
IsLive = true;
}
MainLoop = new GLib.MainLoop ();
bus.AddSignalWatch ();
bus.Message += HandleMessage;
MainLoop.Run ();
// Free resources
Pipeline.SetState (State.Null);
}
static void HandleMessage (object o, MessageArgs args)
{
var msg = args.Message;
switch (msg.Type) {
case MessageType.Error: {
GLib.GException err;
string debug;
msg.ParseError (out err, out debug);
Console.WriteLine ("Error: {0}", err.Message);
Pipeline.SetState (State.Ready);
MainLoop.Quit ();
break;
}
case MessageType.Eos:
// end-of-stream
Pipeline.SetState (State.Ready);
MainLoop.Quit ();
break;
case MessageType.Buffering: {
int percent = 0;
// If the stream is live, we do not care about buffering.
if (IsLive) break;
percent = msg.ParseBuffering ();
Console.WriteLine ("Buffering ({0})", percent);
// Wait until buffering is complete before start/resume playing
if (percent < 100)
Pipeline.SetState (State.Paused);
else
Pipeline.SetState (State.Playing);
break;
}
case MessageType.ClockLost:
// Get a new clock
Pipeline.SetState (State.Paused);
Pipeline.SetState (State.Playing);
break;
default:
// Unhandled message
break;
}
}
}
}
@@ -0,0 +1,121 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
static bool Playing; // Playing or Paused
static double Rate; //Current playback rate (can be negative)
static Element Pipeline, VideoSink;
// Send seek event to change rate
static void SendSeekEvent () {
var format = Format.Time;
long position;
// Obtain the current position, needed for the seek event
if (!Pipeline.QueryPosition (format, out position)) {
Console.WriteLine ("Unable to retrieve current position.");
return;
}
Event seekEvent;
// Create the seek event
if (Rate > 0) {
seekEvent = Event.NewSeek (Rate, Format.Time, SeekFlags.Flush | SeekFlags.Accurate, SeekType.Set, position, SeekType.None, 0);
} else {
seekEvent = Event.NewSeek (Rate, Format.Time, SeekFlags.Flush | SeekFlags.Accurate, SeekType.Set, 0, SeekType.Set, position);
}
if (VideoSink == null) {
// If we have not done so, obtain the sink through which we will send the seek events
VideoSink = (Element)Pipeline ["video-sink"];
}
// Send the event
VideoSink.SendEvent (seekEvent);
Console.WriteLine ("Current rate: {0}", Rate);
}
// Process keyboard input
static void HandleKeyboard () {
ConsoleKeyInfo x;
bool terminate = false;
while (!terminate) {
x = Console.ReadKey ();
switch (x.Key) {
case ConsoleKey.P :
Playing = !Playing;
Pipeline.SetState (Playing ? State.Playing : State.Paused);
Console.WriteLine ("Setting state to {0}", Playing ? "PLAYING" : "PAUSE");
break;
case ConsoleKey.S:
if (x.Modifiers == ConsoleModifiers.Shift)
Rate *= 2.0;
else
Rate /= 2.0;
SendSeekEvent ();
break;
case ConsoleKey.D:
Rate *= -1.0;
SendSeekEvent ();
break;
case ConsoleKey.N:
if (VideoSink == null) {
// If we have not done so, obtain the sink through which we will send the step events
VideoSink = (Element)Pipeline ["video-sink"];
}
var evnt = Event.NewStep (Format.Buffers, 1, Rate, true, false);
VideoSink.SendEvent (evnt);
Console.WriteLine ("Stepping one frame");
break;
case ConsoleKey.Q:
terminate = true;
break;
default:
break;
}
}
}
public static void Main (string[] args)
{
// Initialize GStreamer
Application.Init (ref args);
// Print usage map
Console.WriteLine ("USAGE: Choose one of the following options, then press enter:");
Console.WriteLine (" 'P' to toggle between PAUSE and PLAY");
Console.WriteLine (" 'S' to increase playback speed, 's' to decrease playback speed");
Console.WriteLine (" 'D' to toggle playback direction");
Console.WriteLine (" 'N' to move to next frame (in the current direction, better in PAUSE)");
Console.WriteLine (" 'Q' to quit");
// Build the pipeline
//Pipeline = Parse.Launch ("playbin uri=http://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4");
Pipeline = Parse.Launch ("playbin uri=file:///home/stephan/Downloads/sintel_trailer-1080p.mp4");
// Start playing
var ret = Pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
Playing = true;
Rate = 1.0;
// Process input
HandleKeyboard ();
// Free resources
Pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,72 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
namespace GstreamerSharp
{
class Playback
{
public static void Main (string[] args)
{
// Initialize Gstreamer
Application.Init(ref args);
// Build the pipeline
var source = ElementFactory.Make ("videotestsrc", "source");
var sink = ElementFactory.Make ("autovideosink", "sink");
// Create the empty pipeline
var pipeline = new Pipeline ("test-pipeline");
if (pipeline == null || source == null || sink == null) {
Console.WriteLine ("Not all elements could be created");
return;
}
// Build the pipeline
pipeline.Add (source, sink);
if (!source.Link (sink)) {
Console.WriteLine ("Elements could not be linked");
return;
}
// Modify the source's properties
source ["pattern"] = 0;
// Start playing
var ret = pipeline.SetState(State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state");
return;
}
// Wait until error or EOS
var bus = pipeline.Bus;
var msg = bus.TimedPopFiltered (Constants.CLOCK_TIME_NONE, MessageType.Eos | MessageType.Error);
// Free resources
if (msg != null) {
switch (msg.Type) {
case MessageType.Error:
GLib.GException exc;
string debug;
msg.ParseError (out exc, out debug);
Console.WriteLine (String.Format ("Error received from element {0}: {1}", msg.Src.Name, exc.Message));
Console.WriteLine (String.Format ("Debugging information {0}", debug));
break;
case MessageType.Eos:
Console.WriteLine ("End-Of-Stream reached");
break;
default:
// We should not reach here because we only asked for ERRORs and EOS
Console.WriteLine ("Unexpected messag received");
break;
}
}
pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,125 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
namespace GstreamerSharp
{
class Playback
{
static Pipeline pipeline;
static Element source;
static Element convert;
static Element sink;
public static void Main (string[] args)
{
// Initialize Gstreamer
Application.Init(ref args);
// Create the elements
source = ElementFactory.Make ("uridecodebin", "source");
convert = ElementFactory.Make ("audioconvert", "convert");
sink = ElementFactory.Make ("autoaudiosink", "sink");
// Create the empty pipeline
pipeline = new Pipeline ("test-pipeline");
if (source == null || convert == null || sink == null || pipeline == null) {
Console.WriteLine ("Not all elements could be created");
return;
}
// Build the pipeline. Note that we are NOT linking the source at this point.
// We will do it later.
pipeline.Add (source, convert, sink);
if (!convert.Link (sink)) {
Console.WriteLine ("Elements could not be linked");
return;
}
// Set the URI to play
source ["uri"] = "http://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4";
// Connect to the pad-added signal
source.PadAdded += HandlePadAdded;
// Start playing
var ret = pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
// Listen to the bus
var bus = pipeline.Bus;
bool terminated = false;
do {
var msg = bus.TimedPopFiltered (Constants.CLOCK_TIME_NONE, MessageType.StateChanged | MessageType.Error | MessageType.Eos);
if (msg != null) {
switch (msg.Type) {
case MessageType.Error:
string debug;
GLib.GException exc;
msg.ParseError (out exc, out debug);
Console.WriteLine (string.Format ("Error received from element {0}: {1}", msg.Src.Name, exc.Message));
Console.WriteLine ("Debugging information: {0}", debug);
terminated = true;
break;
case MessageType.Eos:
Console.WriteLine("End-Of-Stream reached.");
terminated = true;
break;
case MessageType.StateChanged:
// We are only interested in state-changed messages from the pipeline
if (msg.Src == pipeline) {
State oldState, newState, pendingState;
msg.ParseStateChanged(out oldState, out newState, out pendingState);
Console.WriteLine ("Pipeline state changed from {0} to {1}:", Element.StateGetName(oldState), Element.StateGetName(newState));
}
break;
default:
// We should not reach here
Console.WriteLine ("Unexpected message received.");
break;
}
}
} while (!terminated);
pipeline.SetState (State.Null);
}
static void HandlePadAdded (object o, PadAddedArgs args)
{
var src = (Element)o;
var newPad = args.NewPad;
var sinkPad = convert.GetStaticPad ("sink");
Console.WriteLine (string.Format ("Received new pad '{0}' from '{1}':", newPad.Name, src.Name));
// If our converter is already linked, we have nothing to do here
if (sinkPad.IsLinked) {
Console.WriteLine ("We are already linked. Ignoring.");
return;
}
// Check the new pad's type
var newPadCaps = newPad.Caps;
var newPadStruct = newPadCaps.GetStructure (0);
var newPadType = newPadStruct.Name;
if (!newPadType.StartsWith ("audio/x-raw")) {
Console.WriteLine ("It has type '{0}' which is not raw audio. Ignoring.", newPadType);
return;
}
// Attempt the link
var ret = newPad.Link (sinkPad);
if (ret != PadLinkReturn.Ok)
Console.WriteLine ("Type is '{0} but link failed.", newPadType);
else
Console.WriteLine ("Link succeeded (type '{0}').", newPadType);
}
}
}
@@ -0,0 +1,136 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
namespace GstreamerSharp
{
class Playback
{
static Element playbin;
static bool playing;
static bool terminate;
static bool seekEnabled;
static bool seekDone;
static long duration;
public static void Main (string[] args)
{
// Initialize Gstreamer
Application.Init(ref args);
// Create the elements
playbin = ElementFactory.Make ("playbin", "playbin");
if (playbin == null) {
Console.WriteLine ("Not all elements could be created");
return;
}
// Set the URI to play.
playbin ["uri"] = "http://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4";
// Start playing
var ret = playbin.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
// Listen to the bus
var bus = playbin.Bus;
do {
var msg = bus.TimedPopFiltered (100 * Constants.MSECOND, MessageType.StateChanged | MessageType.Error | MessageType.DurationChanged);
// Parse message
if (msg != null) {
HandleMessage (msg);
}
else {
// We got no message, this means the timeout expired
if (playing) {
var fmt = Format.Time;
var current = -1L;
// Query the current position of the stream
if (!playbin.QueryPosition (fmt, out current)) {
Console.WriteLine ("Could not query current position.");
}
// if we didn't know it yet, query the stream position
if (duration <= 0) {
if (!playbin.QueryDuration (fmt, out duration)) {
Console.WriteLine ("Could not query current duration.");
}
}
// Print current position and total duration
Console.Write("Position {0} / {1}\r", new TimeSpan (current), new TimeSpan (duration));
if (seekEnabled && !seekDone && current > 10L * Constants.SECOND) {
Console.WriteLine ("\nRead 10s, performing seek...");
playbin.SeekSimple (fmt, SeekFlags.KeyUnit | SeekFlags.Flush, 30L * Constants.SECOND);
seekDone = true;
}
}
}
} while (!terminate);
}
private static void HandleMessage (Message msg) {
switch (msg.Type) {
case MessageType.Error:
string debug;
GLib.GException exc;
msg.ParseError (out exc, out debug);
Console.WriteLine (string.Format ("Error received from element {0}: {1}", msg.Src.Name, exc.Message));
Console.WriteLine ("Debugging information: {0}", debug);
terminate = true;
break;
case MessageType.Eos:
Console.WriteLine("End-Of-Stream reached.");
terminate = true;
break;
case MessageType.DurationChanged:
// The duration has changed, mark the current one as invalid
duration = -1;
break;
case MessageType.StateChanged:
// We are only interested in state-changed messages from the pipeline
if (msg.Src == playbin) {
State oldState, newState, pendingState;
msg.ParseStateChanged(out oldState, out newState, out pendingState);
Console.WriteLine ("Pipeline state changed from {0} to {1}:", Element.StateGetName(oldState), Element.StateGetName(newState));
// Remember wheather we are in the PLAYING state
playing = newState == State.Playing;
if (playing) {
// We have just moved to PLAYING. Check if seeking is possible
var query = Query.NewSeeking (Format.Time);
long start, end;
Format fmt = Format.Time;
if (playbin.Query (query)) {
query.ParseSeeking (out fmt, out seekEnabled, out start, out end);
if (seekEnabled) {
Console.WriteLine ("Seeking is ENABLED from {0} to {1}", new TimeSpan(start), new TimeSpan(end));
} else {
Console.WriteLine ("Seeking DISABLED for this stream.");
}
} else {
Console.WriteLine ("Seeking query failed.");
}
}
}
break;
default:
// We should not reach here
Console.WriteLine ("Unexpected message received.");
break;
}
}
}
}
@@ -0,0 +1,367 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using Gtk;
using System.Runtime.InteropServices;
using Gst.Video;
namespace GstreamerSharp
{
class Playback
{
static Element Playbin;
static Gtk.Range Slider;
static TextView StreamsList;
static ulong silderUpdateSignalID;
static State State;
static long Duration = -1;
static int ignoreCount = 0;
static void HandleValueChanged (object sender, EventArgs e)
{
var range = (Gtk.Range)sender;
var value = range.Value;
Playbin.SeekSimple (Format.Time, SeekFlags.Flush | SeekFlags.KeyUnit, (long)(value * Gst.Constants.SECOND));
}
// This method is called when the STOP button is clicked
static void HandleStop (object sender, EventArgs e)
{
Playbin.SetState (State.Ready);
}
// This method is called when the PAUSE button is clicked
static void HandlePause (object sender, EventArgs e)
{
Playbin.SetState (State.Paused);
}
// This method is called when the PLAY button is clicked
static void HandlePlay (object sender, EventArgs e)
{
Playbin.SetState (State.Playing);
}
static void HandleRealized (object sender, EventArgs e)
{
var widget = (Widget)sender;
var window = widget.Window;
IntPtr windowID = IntPtr.Zero;
// Retrieve window handler from GDK
switch (System.Environment.OSVersion.Platform) {
case PlatformID.Unix:
windowID = gdk_x11_window_get_xid (window.Handle);
break;
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
windowID = gdk_win32_drawable_get_handle (window.Handle);
break;
}
Element overlay = null;
if(Playbin is Gst.Bin)
overlay = ((Gst.Bin) Playbin).GetByInterface (VideoOverlayAdapter.GType);
VideoOverlayAdapter adapter = new VideoOverlayAdapter (overlay.Handle);
adapter.WindowHandle = windowID;
adapter.HandleEvents (true);
}
// This function is called when the main window is closed
static void HandleDelete (object o, DeleteEventArgs args)
{
HandleStop (null, null);
Gtk.Application.Quit ();
}
//This function is called everytime the video window needs to be redrawn (due to damage/exposure, rescaling, etc). GStreamer takes care of this in the PAUSED and PLAYING states, otherwise, we simply draw a black rectangle to avoid garbage showing up. */
static void HandleDamage (object o, DamageEventArgs args)
{
var widget = (Widget)o;
if (State != State.Paused && State != State.Playing) {
var window = widget.Window;
var allocation = widget.Allocation;
var cr = Gdk.CairoHelper.Create (window);
cr.SetSourceRGB (0, 0, 0);
cr.Rectangle (0, 0, allocation.Width, allocation.Height);
cr.Fill ();
cr.Dispose ();
}
args.RetVal = false;
}
static void CreateUI () {
var mainWindow = new Window (WindowType.Toplevel);
mainWindow.DeleteEvent += HandleDelete;
var videoWindow = new DrawingArea ();
videoWindow.DoubleBuffered = false;
videoWindow.Realized += HandleRealized;
videoWindow.DamageEvent += HandleDamage;
var playButton = new Button (Stock.MediaPlay);
playButton.Clicked += HandlePlay;
var pauseButton = new Button (Stock.MediaPause);
pauseButton.Clicked += HandlePause;
var stopButton = new Button (Stock.MediaStop);
stopButton.Clicked += HandleStop;
Slider = new HScale (0, 100, 1);
((Scale)Slider).DrawValue = false;
Slider.ValueChanged += HandleValueChanged;
StreamsList = new TextView ();
StreamsList.Editable = false;
var controls = new HBox (false, 0);
controls.PackStart (playButton, false, false, 2);
controls.PackStart (pauseButton, false, false, 2);
controls.PackStart (stopButton, false, false, 2);
controls.PackStart (Slider, true, true, 2);
var mainHBox = new HBox (false, 0);
mainHBox.PackStart (videoWindow, true, true, 0);
mainHBox.PackStart (StreamsList, false, false, 2);
var mainBox = new VBox (false, 0);
mainBox.PackStart (mainHBox, true, true, 0);
mainBox.PackStart (controls, false, false, 0);
mainWindow.Add (mainBox);
mainWindow.SetDefaultSize (640, 480);
mainWindow.ShowAll ();
}
// This function is called periodically to refresh the GUI
static bool RefreshUI () {
var fmt = Format.Time;
long current = 0;
// We do not want to update anything nless we are in the PAUSED or PLAYING states
if (State != State.Playing && State != State.Paused)
return true;
// If we didn't know it yet, query the stream duration
if (Duration < 0) {
if (!Playbin.QueryDuration (fmt, out Duration))
Console.WriteLine ("Could not query the current duration.");
else {
// Set the range of the silder to the clip duration, in SECONDS
Slider.SetRange (0, Duration / (double)Gst.Constants.SECOND);
}
}
if (Playbin.QueryPosition (fmt, out current)) {
// Block the "value-changed" signal, so the HandleSlider function is not called (which would trigger a seek the user has not requested)
ignoreCount++;
Slider.ValueChanged -= HandleValueChanged;
// Set the position of the slider to the current pipeline position, in SECONDS
Slider.Value = current / (double)Gst.Constants.SECOND;
Slider.ValueChanged += HandleValueChanged;
}
return true;
}
// This function is called when an error message is posted on the bus
static void HandleTags (object sender, GLib.SignalArgs args) {
// We are possibly in the Gstreamer working thread, so we notify the main thread of this event through a message in the bus
var s = new Structure ("tags-changed");
Playbin.PostMessage (Message.NewApplication (Playbin, s));
}
// This function is called when an error message is posted on the bus
static void HandleError (object sender, GLib.SignalArgs args) {
var msg = (Message)args.Args [0];
string debug;
GLib.GException exc;
msg.ParseError (out exc, out debug);
Console.WriteLine (string.Format ("Error received from element {0}: {1}", msg.Src.Name, exc.Message));
Console.WriteLine ("Debugging information: {0}", debug);
// Set the pipeline to READY (which stops playback)
Playbin.SetState (State.Ready);
}
// This function is called when an End-Of-Stream message is posted on the bus. We just set the pipelien to READY (which stops playback)
static void HandleEos (object sender, GLib.SignalArgs args) {
Console.WriteLine ("End-Of-Stream reached.");
Playbin.SetState (State.Ready);
}
// This function is called when the pipeline changes states. We use it to keep track of the current state.
static void HandleStateChanged (object sender, GLib.SignalArgs args) {
var msg = (Message) args.Args [0];
State oldState, newState, pendingState;
msg.ParseStateChanged (out oldState, out newState, out pendingState);
if (msg.Src == Playbin) {
State = newState;
Console.WriteLine ("State set to {0}", Element.StateGetName (newState));
if (oldState == State.Ready && newState == State.Paused) {
// For extra responsiveness, we refresh the GUI as soon as we reach the PAUSED state
RefreshUI ();
}
}
}
// Extract metadata from all the streams and write it to the text widget in the GUI
static void AnalyzeStreams () {
TagList tags;
String str, totalStr;
uint rate;
// Clean current contents of the widget
var text = StreamsList.Buffer;
text.Text = String.Empty;
// Read some properties
var nVideo = (int) Playbin ["n-video"];
var nAudio = (int) Playbin ["n-audio"];
var nText = (int) Playbin ["n-text"];
for (int i = 0; i < nVideo; i++) {
// Retrieve the stream's video tags
tags = (TagList)Playbin.Emit ("get-video-tags", i);
if (tags != null) {
totalStr = string.Format ("video stream {0}:\n", i);
text.InsertAtCursor (totalStr);
tags.GetString (Gst.Constants.TAG_VIDEO_CODEC, out str);
totalStr = string.Format (" codec: {0}\n", str != null ? str : "unknown");
text.InsertAtCursor (totalStr);
}
}
for (int i = 0; i < nAudio; i++) {
// Retrieve the stream's audio tags
tags = (TagList)Playbin.Emit ("get-audio-tags", i);
if (tags != null) {
totalStr = string.Format ("audio stream {0}:\n", i);
text.InsertAtCursor (totalStr);
str = String.Empty;
if (tags.GetString (Gst.Constants.TAG_AUDIO_CODEC, out str)) {
totalStr = string.Format (" codec: {0}\n", str);
text.InsertAtCursor (totalStr);
}
str = String.Empty;
if (tags.GetString (Gst.Constants.TAG_LANGUAGE_CODE+"dr", out str)) {
totalStr = string.Format (" language: {0}\n", str);
text.InsertAtCursor (totalStr);
}
str = String.Empty;
if (tags.GetUint (Gst.Constants.TAG_BITRATE, out rate)) {
totalStr = string.Format (" bitrate: {0}\n", rate);
text.InsertAtCursor (totalStr);
}
}
}
for (int i = 0; i < nText; i++) {
// Retrieve the stream's text tags
tags = (TagList)Playbin.Emit ("get-text-tags", i);
if (tags != null) {
totalStr = string.Format ("subtitle stream {0}:\n", i);
text.InsertAtCursor (totalStr);
if (tags.GetString (Gst.Constants.TAG_LANGUAGE_CODE, out str)) {
totalStr = string.Format (" language: {0}\n", str);
text.InsertAtCursor (totalStr);
}
}
}
}
// This function is called when an "application" message is posted on the bus. Here we retrieve the message posted by the HandleTags callback
static void HandleApplication (object sender, GLib.SignalArgs args) {
var msg = (Message)args.Args [0];
if (msg.Structure.Name.Equals ("tags-changed")) {
// If the message is the "tags-changed" (only one we are currently issuing), update the stream info GUI
AnalyzeStreams ();
}
}
public static void Main (string[] args)
{
// Initialize GTK
Gtk.Application.Init ();
// Initialize Gstreamer
Gst.Application.Init(ref args);
// Create the elements
Playbin = ElementFactory.Make ("playbin", "playbin");
if (Playbin == null) {
Console.WriteLine ("Not all elements could be created");
return;
}
// Set the URI to play.
Playbin ["uri"] = "http://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4";
// Connect to interesting signals in playbin
Playbin.Connect ("video-tags-changed", HandleTags);
Playbin.Connect ("audio-tags-changed", HandleTags);
Playbin.Connect ("text-tags-changed", HandleTags);
// Create the GUI
CreateUI ();
// Instruct the bus to emit signals for each received message, and connect to the interesting signals
var bus = Playbin.Bus;
bus.AddSignalWatch ();
bus.Connect ("message::error", HandleError);
bus.Connect ("message::eos", HandleEos);
bus.Connect ("message::state-changed", HandleStateChanged);
bus.Connect ("message::application", HandleApplication);
// Start playing
var ret = Playbin.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
// Register a function that GLib will call every second
GLib.Timeout.Add (1, RefreshUI);
// Start the GTK main loop- We will not regain control until gtk_main_quit is called
Gtk.Application.Run ();
// Free resources
Playbin.SetState (State.Null);
}
[DllImport ("libgdk-3.so.0") ]
static extern IntPtr gdk_x11_window_get_xid (IntPtr handle);
[DllImport ("gdk-win32-3.0-0.dll") ]
static extern IntPtr gdk_win32_drawable_get_handle (IntPtr handle);
[DllImport ("libX11.so.6")]
static extern int XInitThreads ();
}
}
@@ -0,0 +1,196 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
// Functions below print the capabilities in a human-friendly format
static void PrintCaps (Caps caps, string pfx) {
if (caps == null)
return;
if (caps.IsAny) {
Console.WriteLine ("{0}ANY", pfx);
return;
}
if (caps.IsEmpty) {
Console.WriteLine ("{0}EMPTY", pfx);
return;
}
for (uint i = 0; i < caps.Size; i++) {
var structure = caps.GetStructure (i);
Console.WriteLine ("{0}{1}", pfx, structure.Name);
structure.Foreach ((field_id, value) => {
var ptr = g_quark_to_string (field_id);
var quark = GLib.Marshaller.Utf8PtrToString (ptr);
Console.WriteLine ("{0} {1}: {2}", pfx, quark, value.Val);
return true;
});
}
}
// Prints information about a Pad Template, including its Capabilities*/
static void PrintPadTemplateInformation (ElementFactory factory) {
Console.WriteLine ("Pad Templates for {0}:", factory.Name);
if (factory.NumPadTemplates == 0) {
Console.WriteLine (" none");
return;
}
var pads = factory.StaticPadTemplates;
foreach (var p in pads) {
var pad = (StaticPadTemplate) p;
if (pad.Direction == PadDirection.Src)
Console.WriteLine (" SRC template: '{0}'", pad.NameTemplate);
else if (pad.Direction == PadDirection.Sink)
Console.WriteLine (" SINK template: '{0}'", pad.NameTemplate);
else
Console.WriteLine (" UNKNOWN!!! template: '{0}'", pad.NameTemplate);
if (pad.Presence == PadPresence.Always)
Console.WriteLine (" Availability: Always");
else if (pad.Presence == PadPresence.Sometimes)
Console.WriteLine (" Availability: Sometimes");
else if (pad.Presence == PadPresence.Request) {
Console.WriteLine (" Availability: On request");
} else
Console.WriteLine (" Availability: UNKNOWN!!!");
if (pad.StaticCaps.String != null) {
Console.WriteLine (" Capabilities:");
PrintCaps (pad.StaticCaps.Get (), " ");
}
Console.WriteLine ();
}
}
// Shows the CURRENT capabilities of the requested pad in the given element */
static void PrintPadCapabilities (Element element, string padName) {
// Retrieve pad
var pad = element.GetStaticPad (padName);
if (pad == null) {
Console.WriteLine ("Could not retrieve pad '{0}'", padName);
return;
}
// Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet)
var caps = pad.CurrentCaps;
if (caps == null)
caps = pad.Caps;
/* Print and free */
Console.WriteLine ("Caps for the {0} pad:", padName);
PrintCaps (caps, " ");
}
public static void Main (string[] args)
{
// Initialize Gstreamer
Gst.Application.Init(ref args);
// Create the element factories
var sourceFactory = ElementFactory.Find ("audiotestsrc");
var sinkFactory = ElementFactory.Find ("autoaudiosink");
if (sourceFactory == null || sinkFactory == null) {
Console.WriteLine ("Not all element factories could be created.");
return;
}
// Print information about the pad templates of these factories
PrintPadTemplateInformation (sourceFactory);
PrintPadTemplateInformation (sinkFactory);
// Ask the factories to instantiate actual elements
var source = sourceFactory.Create ("source");
var sink = sinkFactory.Create ("sink");
// Create the empty pipeline
var pipeline = new Pipeline ("test-pipeline");
if (pipeline == null || source == null || sink == null) {
Console.WriteLine ("Not all elements could be created.");
return;
}
// Build the pipeline
pipeline.Add (source, sink);
if (!source.Link (sink)) {
Console.WriteLine ("Elements could not be linked.");
return;
}
// Print initial negotiated caps (in NULL state)
Console.WriteLine ("In NULL state:");
PrintPadCapabilities (sink, "sink");
// Start playing
var ret = pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state (check the bus for error messages).");
}
// Wait until error, EOS or State Change
var bus = pipeline.Bus;
var terminate = false;
do {
var msg = bus.TimedPopFiltered (Constants.CLOCK_TIME_NONE, MessageType.Error | MessageType.Eos | MessageType.StateChanged);
// Parse message
if (msg != null) {
switch (msg.Type) {
case MessageType.Error:
string debug;
GLib.GException exc;
msg.ParseError (out exc, out debug);
Console.WriteLine ("Error received from element {0}: {1}", msg.Src.Name, exc.Message);
Console.WriteLine ("Debugging information: {0}", debug != null ? debug : "none");
terminate = true;
break;
case MessageType.Eos:
Console.WriteLine ("End-Of-Stream reached.\n");
terminate = true;
break;
case MessageType.StateChanged:
// We are only interested in state-changed messages from the pipeline
if (msg.Src == pipeline) {
State oldState, newState, pendingState;
msg.ParseStateChanged (out oldState, out newState, out pendingState);
Console.WriteLine ("Pipeline state changed from {0} to {1}:",
Element.StateGetName (oldState), Element.StateGetName (newState));
// Print the current capabilities of the sink element
PrintPadCapabilities (sink, "sink");
}
break;
default:
// We should not reach here because we only asked for ERRORs, EOS and STATE_CHANGED
Console.WriteLine ("Unexpected message received.");
break;
}
}
} while (!terminate);
// Free resources
pipeline.SetState (State.Null);
}
[DllImport ("glib-2.0.dll")]
static extern IntPtr g_quark_to_string (uint quark);
}
}
@@ -0,0 +1,80 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
public static void Main (string[] args)
{
// Initialize Gstreamer
Gst.Application.Init(ref args);
// Create the elements
var audioSource = ElementFactory.Make ("audiotestsrc", "audio_source");
var tee = ElementFactory.Make ("tee", "tee");
var audioQueue = ElementFactory.Make ("queue", "audio_queue");
var audioConvert = ElementFactory.Make ("audioconvert", "audio_convert");
var audioResample = ElementFactory.Make ("audioresample", "audio_resample");
var audioSink = ElementFactory.Make ("autoaudiosink", "audio_sink");
var videoQueue = ElementFactory.Make ("queue", "video_queue");
var visual = ElementFactory.Make ("wavescope", "visual");
var videoConvert = ElementFactory.Make ("videoconvert", "csp");
var videoSink = ElementFactory.Make ("autovideosink", "video_sink");
// Create the empty pipeline
var pipeline = new Pipeline ("test-pipeline");
if (audioSource == null || tee == null || audioQueue == null || audioConvert == null || audioResample == null ||
audioSink == null || videoQueue == null || visual == null || videoConvert == null || videoSink == null || pipeline == null) {
Console.WriteLine ("Not all elements could be created.");
return;
}
// Link all elements that can be automatically linked because they have "Always" pads
pipeline.Add (audioSource, tee, audioQueue, audioConvert, audioResample, audioSink,
videoQueue, visual, videoConvert, videoSink);
if (!audioSource.Link (tee) ||
!Element.Link (audioQueue, audioConvert, audioResample, audioSink) ||
!Element.Link (videoQueue, visual, videoConvert, videoSink)) {
Console.WriteLine ("Elements could not be linked.");
return;
}
// Manually link the Tee, which has "Request" pads
var teeSrcPadTemplate = tee.GetPadTemplate ("src_%u");
var teeAudioPad = tee.RequestPad (teeSrcPadTemplate, null, null);
Console.WriteLine ("Obtained request pad {0} for audio branch.", teeAudioPad.Name);
var queueAudioPad = audioQueue.GetStaticPad ("sink");
var teeVideoPad = tee.RequestPad (teeSrcPadTemplate, null, null);
Console.WriteLine ("Obtained request pad {0} for video branch.", teeVideoPad.Name);
var queueVideoPad = videoQueue.GetStaticPad ("sink");
if (teeAudioPad.Link (queueAudioPad) != PadLinkReturn.Ok ||
teeVideoPad.Link(queueVideoPad) != PadLinkReturn.Ok) {
Console.WriteLine ("Tee could not be linked.");
return;
}
// Start playing
var ret = pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state (check the bus for error messages).");
}
// Wait until error or EOS
pipeline.Bus.TimedPopFiltered (Constants.CLOCK_TIME_NONE, MessageType.Error | MessageType.Eos);
// Release the request pads from the Tee, and unref them
tee.ReleaseRequestPad (teeAudioPad);
tee.ReleaseRequestPad (teeVideoPad);
// Free resources
pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,229 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
const int ChunkSize = 1024;
const int SampleRate = 44100;
static Gst.App.AppSink AppSink;
static Gst.App.AppSrc AppSource;
static Element Pipeline, Tee, AudioQueue, AudioConvert1, AudioResample, AudioSink;
static Element VideoQueue, AudioConvert2, Visual, VideoConvert, VideoSink;
static Element AppQueue;
static long NumSamples; // Number of samples generated so far (for timestamp generation)
static float a, b, c, d; // For waveform generation
static uint Sourceid; // To control the GSource
static GLib.MainLoop MainLoop; // GLib's Main Loop
// This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
// The idle handler is added to the mainloop when appsrc requests us to start sending data (need-data signal)
// and is removed when appsrc has enough data (enough-data signal).
static bool PushData () {
var numSamples = ChunkSize / 2; // Because each sample is 16 bits
MapInfo map;
// Create a new empty buffer
var buffer = new Gst.Buffer (null, ChunkSize, AllocationParams.Zero);
// Set its timestamp and duration
buffer.Pts = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
buffer.Dts = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
buffer.Duration = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
// Generate some psychodelic waveforms
buffer.Map (out map, MapFlags.Write);
c += d;
d -= c / 1000f;
var freq = 1100f + 1000f * d;
short[] data = new short[numSamples];
for (int i = 0; i < numSamples; i++) {
a += b;
b -= a / freq;
data[i] = (short)(500f * a);
}
// convert the short[] to a byte[] by marshalling
var native = Marshal.AllocHGlobal (data.Length * sizeof(short));
Marshal.Copy (data, 0, native, data.Length);
byte[] bytedata = new byte[2 * data.Length];
Marshal.Copy (native, bytedata, 0, data.Length * sizeof(short));
map.Data = bytedata;
buffer.Unmap (map);
NumSamples += numSamples;
// Push the buffer into the appsrc
var ret = AppSource.PushBuffer (buffer);
// Free the buffer now that we are done with it
buffer.Dispose ();
if (ret != FlowReturn.Ok) {
// We got some error, stop sending data
return false;
}
return true;
}
// This signal callback triggers when appsrc needs Here, we add an idle handler
// to the mainloop to start pushing data into the appsrc
static void StartFeed (object sender, Gst.App.NeedDataArgs args) {
if (Sourceid == 0) {
Console.WriteLine ("Start feeding");
Sourceid = GLib.Idle.Add (PushData);
}
}
// This callback triggers when appsrc has enough data and we can stop sending.
// We remove the idle handler from the mainloop
static void StopFeed (object sender, EventArgs args) {
if (Sourceid != 0) {
Console.WriteLine ("Stop feeding");
GLib.Source.Remove (Sourceid);
Sourceid = 0;
}
}
// The appsink has received a buffer
static void NewSample (object sender, GLib.SignalArgs args) {
var sink = (Gst.App.AppSink)sender;
// Retrieve the buffer
var sample = sink.PullSample ();
if (sample != null) {
// The only thing we do in this example is print a * to indicate a received buffer
Console.Write ("*");
sample.Dispose ();
}
}
// This function is called when an error message is posted on the bus
static void HandleError (object sender, GLib.SignalArgs args) {
GLib.GException err;
string debug;
var msg = (Message) args.Args[0];
// Print error details on the screen
msg.ParseError (out err, out debug);
Console.WriteLine ("Error received from element {0}: {1}", msg.Src.Name, err.Message);
Console.WriteLine ("Debugging information: {0}", debug != null ? debug : "none");
MainLoop.Quit ();
}
public static void Main (string[] args)
{
b = 1;
d = 1;
Gst.Audio.AudioInfo info = new Gst.Audio.AudioInfo();
// Initialize Gstreamer
Gst.Application.Init(ref args);
// Create the elements
AppSource = new Gst.App.AppSrc ("app_src");
Tee = ElementFactory.Make ("tee", "tee");
AudioQueue = ElementFactory.Make ("queue", "audio_queue");
AudioConvert1 = ElementFactory.Make ("audioconvert", "audio_convert1");
AudioResample = ElementFactory.Make ("audioresample", "audio_resample");
AudioSink = ElementFactory.Make ("autoaudiosink", "audio_sink");
VideoQueue = ElementFactory.Make ("queue", "video_queue");
AudioConvert2 = ElementFactory.Make ("audioconvert", "audio_convert2");
Visual = ElementFactory.Make ("wavescope", "visual");
VideoConvert = ElementFactory.Make ("videoconvert", "video_convert");
VideoSink = ElementFactory.Make ("autovideosink", "video_sink");
AppQueue = ElementFactory.Make ("queue", "app_queue");
AppSink = new Gst.App.AppSink ("app_sink");
// Create the empty pipeline
var pipeline = new Pipeline ("test-pipeline");
if (AppSource == null || Tee == null || AudioQueue == null || AudioConvert1 == null || AudioResample == null ||
AudioSink == null || VideoQueue == null || AudioConvert2 == null || Visual == null || VideoConvert == null ||
AppQueue == null || AppSink == null ||pipeline == null) {
Console.WriteLine ("Not all elements could be created.");
return;
}
// Configure wavescope
Visual ["shader"] = 0;
Visual ["style"] = 0;
// Configure appsrc
Gst.Audio.AudioChannelPosition[] position = {};
info.SetFormat (Gst.Audio.AudioFormat.S16, SampleRate, 1, position);
var audioCaps = info.ToCaps ();
AppSource ["caps"] = audioCaps;
AppSource ["format"] = Format.Time;
AppSource.NeedData += StartFeed;
AppSource.EnoughData += StopFeed;
// Configure appsink
AppSink ["emit-signals"] = true;
AppSink ["caps"] = audioCaps;
AppSink.NewSample += NewSample;
// Link all elements that can be automatically linked because they have "Always" pads
pipeline.Add (AppSource, Tee, AudioQueue, AudioConvert1, AudioResample,
AudioSink, VideoQueue, AudioConvert2, Visual, VideoConvert, VideoSink, AppQueue, AppSink);
if (!Element.Link (AppSource, Tee) ||
!Element.Link (AudioQueue, AudioConvert1, AudioResample, AudioSink) ||
!Element.Link (VideoQueue, AudioConvert2, Visual, VideoConvert, VideoSink) ||
!Element.Link (AppQueue, AppSink)) {
Console.WriteLine ("Elements could not be linked.");
return;
}
// Manually link the Tee, which has "Request" pads
var teeSrcPadTemplate = Tee.GetPadTemplate ("src_%u");
var teeAudioPad = Tee.RequestPad (teeSrcPadTemplate);
Console.WriteLine ("Obtained request pad {0} for audio branch.", teeAudioPad.Name);
var queueAudioPad = AudioQueue.GetStaticPad ("sink");
var teeVideoPad = Tee.RequestPad (teeSrcPadTemplate);
Console.WriteLine ("Obtained request pad {0} for video branch.", teeVideoPad.Name);
var queueVideoPad = VideoQueue.GetStaticPad ("sink");
var teeAppPad = Tee.RequestPad (teeSrcPadTemplate);
Console.WriteLine ("Obtained request pad {0} for app branch.", teeAppPad.Name);
var queueAppPad = AppQueue.GetStaticPad ("sink");
if (teeAudioPad.Link (queueAudioPad) != PadLinkReturn.Ok ||
teeVideoPad.Link (queueVideoPad) != PadLinkReturn.Ok ||
teeAppPad.Link (queueAppPad) != PadLinkReturn.Ok) {
Console.WriteLine ("Tee could not be linked");
return;
}
// Instruct the bus to emit signals for each received message, and connect to the interesting signals
var bus = pipeline.Bus;
bus.AddSignalWatch ();
bus.Connect ("message::error", HandleError);
// Start playing the pipeline
pipeline.SetState (State.Playing);
// Create a GLib Main Loop and set it to run
MainLoop = new GLib.MainLoop ();
MainLoop.Run ();
// Release the request pads from the Tee, and unref them
Tee.ReleaseRequestPad(teeAudioPad);
Tee.ReleaseRequestPad(teeVideoPad);
Tee.ReleaseRequestPad(teeAppPad);
// Free resources
pipeline.SetState (State.Null);
Gst.Global.Deinit();
}
}
}
@@ -0,0 +1,180 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using Gst.PbUtils;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
static Discoverer Discoverer;
static GLib.MainLoop MainLoop;
// Print a tag in a human-readable format (name: value)
static void PrintTagForeach (TagList tags, string tag, int depth) {
var val = GLib.Value.Empty;
TagList.CopyValue (ref val, tags, tag);
string str;
if (val.Val is string)
str = (string)val.Val;
else
str = Value.Serialize (val);
Console.WriteLine ("{0}{1}: {2}", new string(' ', 2 * depth), Tag.GetNick (tag), str);
}
// Print information regarding a stream
static void PrintStreamInfo (DiscovererStreamInfo info, int depth) {
var caps = info.Caps;
string desc = null;
if (caps != null) {
if (caps.IsFixed)
desc = Gst.PbUtils.Global.PbUtilsGetCodecDescription (caps);
else
desc = caps.ToString ();
}
Console.WriteLine ("{0}{1}: {2}", new string (' ', 2 * depth), info.StreamTypeNick, (desc != null ? desc : ""));
var tags = info.Tags;
if (tags != null) {
Console.WriteLine ("{0}Tags:", new string (' ', 2 * (depth + 1)));
tags.Foreach ((TagForeachFunc)delegate (TagList list, string tag) {
PrintTagForeach (list, tag, depth + 2);
});
}
}
// Print information regarding a stream and its substreams, if any
static void PrintTopology (DiscovererStreamInfo info, int depth) {
if (info == null)
return;
PrintStreamInfo (info, depth);
var next = info.Next;
if (next != null) {
PrintTopology (next, depth + 1);
} else if (info is DiscovererContainerInfo) {
var streams = ((DiscovererContainerInfo)info).Streams;
foreach (var stream in streams) {
PrintTopology (stream, depth + 1);
}
}
}
//This function is called every time the discoverer has information regarding one of the URIs we provided.
static void HandleDiscovered (object disc, DiscoveredArgs args) {
var info = args.Info;
var uri = info.Uri;
var result = info.Result;
var discoverer = (Discoverer)disc;
switch (result) {
case DiscovererResult.UriInvalid:
Console.WriteLine ("Invalid URI '{0}'", uri);
break;
case DiscovererResult.Error:
var err = new GLib.GException (args.Error);
Console.WriteLine ("Discoverer error: {0}", err.Message);
break;
case DiscovererResult.Timeout:
Console.WriteLine ("Timeout");
break;
case DiscovererResult.Busy:
Console.WriteLine ("Busy");
break;
case DiscovererResult.MissingPlugins:{
var s = info.Misc;
if (s != null) {
Console.WriteLine ("Missing plugins: {0}", s);
}
break;
}
case DiscovererResult.Ok:
Console.WriteLine ("Discovered '{0}'", uri);
break;
}
if (result != DiscovererResult.Ok) {
Console.WriteLine ("This URI cannot be played");
return;
}
// If we got no error, show the retrieved information
Console.WriteLine ("\nDuration: {0}", new TimeSpan((long)info.Duration));
var tags = info.Tags;
if (tags != null) {
Console.WriteLine ("Tags:");
tags.Foreach ((TagForeachFunc)delegate (TagList list, string tag) {
PrintTagForeach (list, tag, 1);
});
}
Console.WriteLine ("Seekable: {0}", (info.Seekable ? "yes" : "no"));
Console.WriteLine ();
var sinfo = info.StreamInfo;
if (sinfo == null)
return;
Console.WriteLine ("Stream information:");
PrintTopology (sinfo, 1);
Console.WriteLine ();
}
public static void Main (string[] args)
{
var uri = "http://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4";
// if a URI was provided, use it instead of the default one
if (args.Length > 1) {
uri = args[0];
}
// Initialize GStreamer
Gst.Application.Init (ref args);
Console.WriteLine ("Discovering '{0}'", uri);
// Instantiate the Discoverer
Discoverer = new Discoverer (5L * Gst.Constants.SECOND);
// Connect to the interesting signals
Discoverer.Discovered += HandleDiscovered;
Discoverer.Finished += (sender, e) => {
Console.WriteLine ("Finished discovering");
MainLoop.Quit ();
};
// Start the discoverer process (nothing to do yet)
Discoverer.Start ();
// Add a request to process asynchronously the URI passed through the command line
if (!Discoverer.DiscoverUriAsync (uri)) {
Console.WriteLine ("Failed to start discovering URI '{0}'", uri);
return;
}
// Create a GLib Main Loop and set it to run, so we can wait for the signals
MainLoop = new GLib.MainLoop ();
MainLoop.Run ();
// Stop the discoverer process
Discoverer.Stop ();
}
}
}
@@ -0,0 +1,115 @@
using GLib;
using Gst;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace GstreamerSharp
{
class Program
{
static void Main(string[] args)
{
Gst.Application.Init(ref args);
Element src = ElementFactory.Make("audiotestsrc");
Element convert = ElementFactory.Make("audioconvert");
Element volume = new ExampleVolume();
Element sink = ElementFactory.Make("autoaudiosink");
Pipeline pipeline = new Pipeline();
pipeline.Add(src, convert, volume, sink);
Element.Link(src, convert, volume, sink);
pipeline.SetState(State.Playing);
MainLoop loop = new MainLoop();
loop.Run();
pipeline.SetState(State.Null);
Console.ReadLine();
}
}
class ExampleVolume : Element
{
public ExampleVolume()
{
Volume = 0.5;
_sink = new Pad(__sinkTemplate, "sink");
_sink.ChainFunctionFull = Chain;
_sink.Flags |= PadFlags.ProxyCaps;
AddPad(_sink);
_src = new Pad(__srcTemplate, "src");
_src.Flags |= PadFlags.ProxyCaps;
AddPad(_src);
}
public double Volume { get; set; }
FlowReturn Chain(Pad pad, Gst.Object parent, Gst.Buffer buffer)
{
if (Volume == 1.0)
{
return _src.Push(buffer);
}
buffer.MakeWritable();
MapInfo mapInfo;
buffer.Map(out mapInfo, MapFlags.Read | MapFlags.Write);
ScaleInt16(mapInfo.DataPtr, mapInfo.Size / 2, Volume);
buffer.Unmap(mapInfo);
return _src.Push(buffer);
}
private unsafe void ScaleInt16(IntPtr data, ulong size, double volume)
{
Int16* sample = (Int16*)data;
for (ulong i = 0; i < size; i++)
{
*sample = ClampInt16(*sample * volume);
sample++;
}
}
private Int16 ClampInt16(double d)
{
int i = (int)Math.Round(d);
if (i > Int16.MaxValue)
{
return Int16.MaxValue;
}
else if (i < Int16.MinValue)
{
return Int16.MinValue;
}
else
{
return (Int16)i;
}
}
Pad _src;
Pad _sink;
static ExampleVolume()
{
Caps audioCaps = Caps.FromString("audio/x-raw, format=(string) S16LE, rate=(int) [1, MAX], channels=(int) 2, layout=(string) interleaved");
__srcTemplate = new PadTemplate("src", PadDirection.Src, PadPresence.Always, audioCaps);
__sinkTemplate = new PadTemplate("sink", PadDirection.Sink, PadPresence.Always, audioCaps);
}
static PadTemplate __srcTemplate;
static PadTemplate __sinkTemplate;
}
}
@@ -0,0 +1,70 @@
// Authors
// Copyright (C) 2017 Thibault Saunier <thibault.saunier@osg-samsung.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301 USA
using System;
using Gst;
using System.Diagnostics;
namespace GESSharp
{
class GESExample
{
public static void Main (string[] args)
{
// Initialize Gstreamer
Gst.Application.Init();
// Build the pipeline
GES.Global.Init();
var pipeline = new GES.Pipeline();
var timeline = GES.Timeline.NewAudioVideo();
var layer = timeline.AppendLayer();
pipeline["timeline"] = timeline;
var clip = new GES.TitleClip();
clip.Duration = Constants.SECOND * 5;
layer.AddClip(clip);
clip.SetChildProperty("text", new GLib.Value("Clip 1"));
var clip1 = new GES.TitleClip();
clip1.Start = Constants.SECOND * 5;
clip1.Duration = Constants.SECOND * 5;
layer.AddClip(clip1);
clip1.SetChildProperty("text", new GLib.Value("Clip 2"));
timeline.Commit();
pipeline.SetState(State.Playing);
//// Wait until error or EOS
var bus = pipeline.Bus;
Message msg = null;
while (msg == null) {
var format = Format.Time;
long position;
msg = bus.TimedPopFiltered (Gst.Constants.SECOND, MessageType.Eos | MessageType.Error);
pipeline.QueryPosition (format, out position);
Console.WriteLine("position: " + Global.TimeFormat(position)
+ " / " + Global.TimeFormat(timeline.Duration));
}
pipeline.SetState(State.Null);
}
}
}
@@ -0,0 +1,96 @@
// Copyright (C) 2013 Stephan Sundermann <stephansundermann@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using Gst;
namespace GstreamerSharp
{
class Playback
{
static GLib.MainLoop Loop;
static Element element;
public static void Main (string[] args)
{
Loop = new GLib.MainLoop();
Application.Init(ref args);
element = Gst.Parse.Launch("playbin uri=http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/Sintel_Trailer1.1080p.DivX_Plus_HD.mkv");
element.Bus.AddSignalWatch();
element.Bus.Message += Handle;
element.SetState(State.Playing);
Loop.Run();
}
static void Handle (object e, MessageArgs args)
{
switch (args.Message.Type) {
case MessageType.StateChanged:
State oldstate, newstate, pendingstate;
args.Message.ParseStateChanged (out oldstate, out newstate, out pendingstate);
System.Console.WriteLine ("[StateChange] From " + oldstate + " to " + newstate + " pending at " + pendingstate);
break;
case MessageType.StreamStatus:
Element owner;
StreamStatusType type;
args.Message.ParseStreamStatus (out type, out owner);
System.Console.WriteLine ("[StreamStatus] Type" + type + " from " + owner);
break;
case MessageType.DurationChanged:
long duration;
element.QueryDuration (Format.Time, out duration);
System.Console.WriteLine ("[DurationChanged] New duration is " + (duration / Constants.SECOND) + " seconds");
break;
case MessageType.ResetTime:
ulong runningtime = args.Message.ParseResetTime ();
System.Console.WriteLine ("[ResetTime] Running time is " + runningtime);
break;
case MessageType.AsyncDone:
ulong desiredrunningtime = args.Message.ParseAsyncDone ();
System.Console.WriteLine ("[AsyncDone] Running time is " + desiredrunningtime);
break;
case MessageType.NewClock:
Clock clock = args.Message.ParseNewClock ();
System.Console.WriteLine ("[NewClock] " + clock);
break;
case MessageType.Buffering:
int percent = args.Message.ParseBuffering ();
System.Console.WriteLine ("[Buffering] " + percent + " % done");
break;
case MessageType.Tag:
TagList list = args.Message.ParseTag ();
System.Console.WriteLine ("[Tag] Information in scope " + list.Scope + " is " + list.ToString());
break;
case MessageType.Error:
GLib.GException gerror;
string debug;
args.Message.ParseError (out gerror, out debug);
System.Console.WriteLine ("[Error] " + gerror.Message + " debug information " + debug + ". Exiting! ");
Loop.Quit ();
break;
case MessageType.Eos:
System.Console.WriteLine ("[Eos] Playback has ended. Exiting!");
Loop.Quit ();
break;
default:
System.Console.WriteLine ("[Recv] " + args.Message.Type);
break;
}
}
}
}
@@ -0,0 +1,186 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
// playbin flags
static uint Video = (1 << 0); // We want video output
static uint Audio = (1 << 1); // We want audio output
static uint Text = (1 << 2); // We want subtitle output
static Element Playbin;
static int NAudio, NVideo, NText;
static int CurrentVideo, CurrentAudio, CurrentText;
static GLib.MainLoop MainLoop;
public static void Main (string[] args)
{
// Initialize GStreamer
Application.Init (ref args);
// Create the elements
Playbin = ElementFactory.Make ("playbin", "playbin");
if (Playbin == null) {
Console.WriteLine ("Not all elements could be created.");
return;
}
// Set the URI to play
Playbin ["uri"] = "http://freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm";
// Set flags to show Audio and Video but ignore Subtitles
var flags = (uint)Playbin ["flags"];
flags |= Audio | Video;
flags &= ~Text;
Playbin ["flags"] = flags;
// Set connection speed. This will affect some internal decisions of playbin2
Playbin ["connection-speed"] = 56;
// Add a bus watch, so we get notified when a message arrives
var bus = Playbin.Bus;
bus.AddSignalWatch ();
bus.Message += HandleMessage;
// Start playing
var ret = Playbin.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
// Add a keyboard watch so we get notified of keystrokes
GLib.Idle.Add (HandleKeyboard);
MainLoop = new GLib.MainLoop ();
MainLoop.Run ();
// Free resources
Playbin.SetState (State.Null);
}
static void HandleMessage (object o, MessageArgs args)
{
var msg = args.Message;
switch (msg.Type) {
case MessageType.Error:
GLib.GException err;
string debug;
msg.ParseError (out err, out debug);
Console.WriteLine ("Error received from element {0}: {1}", msg.Src, err.Message);
Console.WriteLine ("Debugging information: {0}", debug != null ? debug : "none");
MainLoop.Quit ();
break;
case MessageType.Eos:
Console.WriteLine ("End-Of-Stream reached.");
MainLoop.Quit ();
break;
case MessageType.StateChanged: {
State oldState, newState, pendingState;
msg.ParseStateChanged (out oldState, out newState, out pendingState);
if (msg.Src == Playbin) {
if (newState == State.Playing) {
// Once we are in the playing state, analyze the streams
AnalyzeStreams ();
}
}
} break;
default:
break;
}
// We want to keep receiving messages
args.RetVal = true;
}
// Extract some metadata from the streams and print it on the screen
static void AnalyzeStreams () {
// Read some properties
NVideo = (int)Playbin ["n-video"];
NAudio = (int)Playbin ["n-audio"];
NText = (int)Playbin ["n-text"];
Console.WriteLine ("{0} video stream(s), {1} audio stream(s), {2} text stream(s)", NVideo, NAudio, NText);
Console.WriteLine ();
for (int i = 0; i < NVideo; i++) {
// Retrieve the stream's video tags
var tags = (TagList)Playbin.Emit ("get-video-tags", new object [] { i });
if (tags != null) {
Console.WriteLine ("video stream {0}", i);
string str;
tags.GetString (Constants.TAG_VIDEO_CODEC, out str);
Console.WriteLine (" codec: {0}", str != null ? str : "unknown");
}
}
Console.WriteLine ();
for (int i = 0; i < NAudio; i++) {
// Retrieve the stream's audio tags
var tags = (TagList)Playbin.Emit ("get-audio-tags", new object [] { i });
if (tags != null) {
Console.WriteLine ("audio stream {0}", i);
string str;
if (tags.GetString (Constants.TAG_AUDIO_CODEC, out str)) {
Console.WriteLine (" codec: {0}", str);
}
if (tags.GetString (Constants.TAG_LANGUAGE_CODE, out str)) {
Console.WriteLine (" language: {0}", str);
}
uint rate;
if (tags.GetUint (Constants.TAG_BITRATE, out rate)) {
Console.WriteLine (" bitrate: {0}", rate);
}
}
}
Console.WriteLine ();
for (int i = 0; i < NText; i++) {
// Retrieve the stream's subtitle tags
var tags = (TagList)Playbin.Emit ("get-text-tags", new object [] { i });
if (tags != null) {
Console.WriteLine ("subtitle stream {0}", i);
string str;
if (tags.GetString (Constants.TAG_LANGUAGE_CODE, out str)) {
Console.WriteLine (" language: {0}", str);
}
}
}
CurrentAudio = (int)Playbin ["current-audio"];
CurrentVideo = (int)Playbin ["current-video"];
CurrentText = (int)Playbin ["current-text"];
Console.WriteLine ();
Console.WriteLine ("Currently playing video stream {0}, audio stream {1} and text stream {2}", CurrentVideo, CurrentAudio, CurrentText);
Console.WriteLine ("Type any number to select a different audio stream");
}
// Process keyboard input
static bool HandleKeyboard () {
if (Console.KeyAvailable) {
var key = Console.ReadKey (false);
if (char.IsDigit (key.KeyChar)) {
var digit = int.Parse (key.KeyChar.ToString ());
if (digit < 0 || digit > NAudio) {
Console.WriteLine ("Index out of bounds");
} else {
// If the input was a valid audio stream index, set the current audio stream
Console.WriteLine ("Setting current audio stream to {0}", digit);
Playbin ["current-audio"] = digit;
}
}
}
return true;
}
}
}
@@ -0,0 +1,185 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
// playbin flags
static uint Video = (1 << 0); // We want video output
static uint Audio = (1 << 1); // We want audio output
static uint Text = (1 << 2); // We want subtitle output
static Element Playbin;
static int NAudio, NVideo, NText;
static int CurrentVideo, CurrentAudio, CurrentText;
static GLib.MainLoop MainLoop;
public static void Main (string[] args)
{
// Initialize GStreamer
Application.Init (ref args);
// Create the elements
Playbin = ElementFactory.Make ("playbin", "playbin");
if (Playbin == null) {
Console.WriteLine ("Not all elements could be created.");
return;
}
// Set the URI to play
Playbin ["uri"] = "http://freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.ogv";
// Set the subtitle URI to play and some font description
Playbin ["suburi"] = "http://freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer_gr.srt";
Playbin ["subtitle-font-desc"] = "Sans, 18";
// Set flags to show Audio and Video and Subtitles
var flags = (uint)Playbin ["flags"];
flags |= Audio | Video | Text;
Playbin ["flags"] = flags;
// Add a bus watch, so we get notified when a message arrives
var bus = Playbin.Bus;
bus.AddSignalWatch ();
bus.Message += HandleMessage;
// Start playing
var ret = Playbin.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
// Add a keyboard watch so we get notified of keystrokes
GLib.Idle.Add (HandleKeyboard);
MainLoop = new GLib.MainLoop ();
MainLoop.Run ();
// Free resources
Playbin.SetState (State.Null);
}
static void HandleMessage (object o, MessageArgs args)
{
var msg = args.Message;
switch (msg.Type) {
case MessageType.Error:
GLib.GException err;
string debug;
msg.ParseError (out err, out debug);
Console.WriteLine ("Error received from element {0}: {1}", msg.Src, err.Message);
Console.WriteLine ("Debugging information: {0}", debug != null ? debug : "none");
MainLoop.Quit ();
break;
case MessageType.Eos:
Console.WriteLine ("End-Of-Stream reached.");
MainLoop.Quit ();
break;
case MessageType.StateChanged: {
State oldState, newState, pendingState;
msg.ParseStateChanged (out oldState, out newState, out pendingState);
if (msg.Src == Playbin) {
if (newState == State.Playing) {
// Once we are in the playing state, analyze the streams
AnalyzeStreams ();
}
}
} break;
default:
break;
}
// We want to keep receiving messages
args.RetVal = true;
}
// Extract some metadata from the streams and print it on the screen
static void AnalyzeStreams () {
// Read some properties
NVideo = (int)Playbin ["n-video"];
NAudio = (int)Playbin ["n-audio"];
NText = (int)Playbin ["n-text"];
Console.WriteLine ("{0} video stream(s), {1} audio stream(s), {2} text stream(s)", NVideo, NAudio, NText);
Console.WriteLine ();
for (int i = 0; i < NVideo; i++) {
// Retrieve the stream's video tags
var tags = (TagList)Playbin.Emit ("get-video-tags", new object [] { i });
if (tags != null) {
Console.WriteLine ("video stream {0}", i);
string str;
tags.GetString (Constants.TAG_VIDEO_CODEC, out str);
Console.WriteLine (" codec: {0}", str != null ? str : "unknown");
}
}
Console.WriteLine ();
for (int i = 0; i < NAudio; i++) {
// Retrieve the stream's audio tags
var tags = (TagList)Playbin.Emit ("get-audio-tags", new object [] { i });
if (tags != null) {
Console.WriteLine ("audio stream {0}", i);
string str;
if (tags.GetString (Constants.TAG_AUDIO_CODEC, out str)) {
Console.WriteLine (" codec: {0}", str);
}
if (tags.GetString (Constants.TAG_LANGUAGE_CODE, out str)) {
Console.WriteLine (" language: {0}", str);
}
uint rate;
if (tags.GetUint (Constants.TAG_BITRATE, out rate)) {
Console.WriteLine (" bitrate: {0}", rate);
}
}
}
Console.WriteLine ();
for (int i = 0; i < NText; i++) {
// Retrieve the stream's subtitle tags
var tags = (TagList)Playbin.Emit ("get-text-tags", new object [] { i });
if (tags != null) {
Console.WriteLine ("subtitle stream {0}", i);
string str;
if (tags.GetString (Constants.TAG_LANGUAGE_CODE, out str)) {
Console.WriteLine (" language: {0}", str);
}
}
}
CurrentAudio = (int)Playbin ["current-audio"];
CurrentVideo = (int)Playbin ["current-video"];
CurrentText = (int)Playbin ["current-text"];
Console.WriteLine ();
Console.WriteLine ("Currently playing video stream {0}, audio stream {1} and text stream {2}", CurrentVideo, CurrentAudio, CurrentText);
Console.WriteLine ("Type any number to select a different subtitle stream");
}
// Process keyboard input
static bool HandleKeyboard () {
if (Console.KeyAvailable) {
var key = Console.ReadKey (false);
if (char.IsDigit (key.KeyChar)) {
var digit = int.Parse (key.KeyChar.ToString ());
if (digit < 0 || digit > NText) {
Console.WriteLine ("Index out of bounds");
} else {
// If the input was a valid subtitle stream index, set the current subtitle stream
Console.WriteLine ("Setting current subtitle stream to {0}", digit);
Playbin ["current-text"] = digit;
}
}
}
return true;
}
}
}
@@ -0,0 +1,153 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
namespace GstreamerSharp
{
class Playback
{
const int ChunkSize = 1024;
const int SampleRate = 44100;
static Gst.App.AppSrc AppSource;
static Element Pipeline;
static long NumSamples; // Number of samples generated so far (for timestamp generation)
static float a, b, c, d; // For waveform generation
static uint Sourceid; // To control the GSource
static GLib.MainLoop MainLoop; // GLib's Main Loop
// This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
// The idle handler is added to the mainloop when appsrc requests us to start sending data (need-data signal)
// and is removed when appsrc has enough data (enough-data signal).
static bool PushData () {
var numSamples = ChunkSize / 2; // Because each sample is 16 bits
MapInfo map;
// Create a new empty buffer
var buffer = new Gst.Buffer (null, ChunkSize, AllocationParams.Zero);
// Set its timestamp and duration
buffer.Pts = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
buffer.Dts = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
buffer.Duration = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
// Generate some psychodelic waveforms
buffer.Map (out map, MapFlags.Write);
c += d;
d -= c / 1000f;
var freq = 1100f + 1000f * d;
short[] data = new short[numSamples];
for (int i = 0; i < numSamples; i++) {
a += b;
b -= a / freq;
data[i] = (short)(500f * a);
}
// convert the short[] to a byte[] by marshalling
var native = Marshal.AllocHGlobal (data.Length * sizeof(short));
Marshal.Copy (data, 0, native, data.Length);
byte[] bytedata = new byte[2 * data.Length];
Marshal.Copy (native, bytedata, 0, data.Length * sizeof(short));
map.Data = bytedata;
buffer.Unmap (map);
NumSamples += numSamples;
// Push the buffer into the appsrc
var ret = AppSource.PushBuffer (buffer);
// Free the buffer now that we are done with it
buffer.Dispose ();
if (ret != FlowReturn.Ok) {
// We got some error, stop sending data
return false;
}
return true;
}
// This signal callback triggers when appsrc needs Here, we add an idle handler
// to the mainloop to start pushing data into the appsrc
static void StartFeed (object sender, Gst.App.NeedDataArgs args) {
if (Sourceid == 0) {
Console.WriteLine ("Start feeding");
Sourceid = GLib.Idle.Add (PushData);
}
}
// This callback triggers when appsrc has enough data and we can stop sending.
// We remove the idle handler from the mainloop
static void StopFeed (object sender, EventArgs args) {
if (Sourceid != 0) {
Console.WriteLine ("Stop feeding");
GLib.Source.Remove (Sourceid);
Sourceid = 0;
}
}
// This function is called when playbin has created the appsrc element, so we have a chance to configure it.
static void SourceSetup (object sender, GLib.SignalArgs args) {
var info = new Gst.Audio.AudioInfo ();
var source = new Gst.App.AppSrc(((Element)args.Args [0]).Handle);
Console.WriteLine ("Source has been created. Configuring.");
AppSource = source;
// Configure appsrc
Gst.Audio.AudioChannelPosition[] position = {};
info.SetFormat (Gst.Audio.AudioFormat.S16, SampleRate, 1, position);
var audioCaps = info.ToCaps ();
source ["caps"] = audioCaps;
source ["format"] = Format.Time;
source.NeedData += StartFeed;
source.EnoughData += StopFeed;
}
// This function is called when an error message is posted on the bus
static void HandleError (object sender, GLib.SignalArgs args) {
GLib.GException err;
string debug;
var msg = (Message) args.Args[0];
// Print error details on the screen
msg.ParseError (out err, out debug);
Console.WriteLine ("Error received from element {0}: {1}", msg.Src.Name, err.Message);
Console.WriteLine ("Debugging information: {0}", debug != null ? debug : "none");
MainLoop.Quit ();
}
public static void Main (string[] args)
{
b = 1;
d = 1;
// Initialize Gstreamer
Gst.Application.Init(ref args);
// Create the playbin element
Pipeline = Parse.Launch ("playbin uri=appsrc://");
Pipeline.Connect ("source-setup", SourceSetup);
// Instruct the bus to emit signals for each received message, and connect to the interesting signals
var bus = Pipeline.Bus;
bus.AddSignalWatch ();
bus.Connect ("message::error", HandleError);
// Start playing the pipeline
Pipeline.SetState (State.Playing);
// Create a GLib Main Loop and set it to run
MainLoop = new GLib.MainLoop ();
MainLoop.Run ();
// Free resources
Pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,147 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
using System.Text;
namespace GstreamerSharp
{
class Playback
{
const int GraphLength = 78;
static uint PlayFlagDownload = (1 << 7); // Enable progressive download (on selected formats)
static bool IsLive;
static Element Pipeline;
static GLib.MainLoop MainLoop;
static int BufferingLevel;
static void GotLocation (object sender, GLib.SignalArgs args) {
var propObject = (Gst.Object)args.Args [0];
var location = (string) propObject["temp-location"];
Console.WriteLine ("Temporary file: {0}", location);
// Uncomment this line to keep the temporary file after the program exits
// g_object_set (G_OBJECT (prop_object), "temp-remove", FALSE, NULL);
}
public static void Main (string[] args)
{
// Initialize GStreamer
Application.Init (ref args);
BufferingLevel = 100;
// Build the pipeline
Pipeline = Parse.Launch ("playbin uri=http://freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm");
var bus = Pipeline.Bus;
// Set the download flag
var flags = (uint)Pipeline ["flags"];
flags |= PlayFlagDownload;
Pipeline ["flags"] = flags;
// Uncomment this line to limit the amount of downloaded data
// g_object_set (pipeline, "ring-buffer-max-size", (guint64)4000000, NULL);
// Start playing
var ret = Pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
} else if (ret == StateChangeReturn.NoPreroll) {
IsLive = true;
}
MainLoop = new GLib.MainLoop ();
bus.AddSignalWatch ();
bus.Message += HandleMessage;
Pipeline.Connect ("deep-notify::temp-location", GotLocation);
// Register a function that GLib will call every second
GLib.Timeout.AddSeconds (1, RefreshUI);
MainLoop.Run ();
// Free resources
Pipeline.SetState (State.Null);
}
static void HandleMessage (object o, MessageArgs args)
{
var msg = args.Message;
switch (msg.Type) {
case MessageType.Error: {
GLib.GException err;
string debug;
msg.ParseError (out err, out debug);
Console.WriteLine ("Error: {0}", err.Message);
Pipeline.SetState (State.Ready);
MainLoop.Quit ();
break;
}
case MessageType.Eos:
// end-of-stream
Pipeline.SetState (State.Ready);
MainLoop.Quit ();
break;
case MessageType.Buffering: {
int percent = 0;
// If the stream is live, we do not care about buffering.
if (IsLive) break;
percent = msg.ParseBuffering ();
// Wait until buffering is complete before start/resume playing
if (percent < 100)
Pipeline.SetState (State.Paused);
else
Pipeline.SetState (State.Playing);
break;
}
case MessageType.ClockLost:
// Get a new clock
Pipeline.SetState (State.Paused);
Pipeline.SetState (State.Playing);
break;
default:
// Unhandled message
break;
}
}
static bool RefreshUI () {
var query = new Query (Format.Percent);
if (Pipeline.Query (query)) {
var graph = new StringBuilder (GraphLength);
long position = 0, duration = 0;
var nRanges = query.NBufferingRanges;
for (uint range = 0; range < nRanges; range++) {
long start, stop;
query.ParseNthBufferingRange (range, out start, out stop);
start = start * GraphLength / (stop - start);
stop = stop * GraphLength / (stop - start);
for (int i = (int)start; i < stop; i++)
graph.Insert (i, '-');
}
if (Pipeline.QueryPosition (Format.Time, out position) && position >= 0
&& Pipeline.QueryDuration (Format.Time, out duration) && duration >= 0) {
var i = (int)(GraphLength * (double)position / (double)(duration + 1));
graph [i] = BufferingLevel < 100 ? 'X' : '>';
}
Console.WriteLine ("[{0}]", graph);
if (BufferingLevel < 100) {
Console.WriteLine (" Buffering: {0}", BufferingLevel);
} else {
Console.WriteLine (" ");
}
Console.WriteLine ();
}
return true;
}
}
}
@@ -0,0 +1,126 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
using System.Text;
namespace GstreamerSharp
{
class Playback
{
static Element Pipeline;
static GLib.MainLoop MainLoop;
// Process a color balance command
static void UpdateColorChannel (string channelName, bool increase, Gst.Video.IColorBalance cb) {
// Retrieve the list of channels and locate the requested one
var channels = cb.ListChannels ();
Gst.Video.ColorBalanceChannel channel = null;
foreach (var ch in channels) {
var label = ch.Label;
if (label.Contains (channelName)) {
channel = ch;
break;
}
}
if (channel == null)
return;
// Change the channel's value
var step = 0.1 * (channel.MaxValue - channel.MinValue);
var value = cb.GetValue (channel);
if (increase) {
value = (int)(value + step);
if (value > channel.MaxValue)
value = channel.MaxValue;
} else {
value = (int)(value - step);
if (value < channel.MinValue)
value = channel.MinValue;
}
cb.SetValue (channel, value);
}
// Process keyboard input
static bool HandleKeyboard () {
if (Console.KeyAvailable) {
var key = Console.ReadKey (false);
var cb = new Gst.Video.ColorBalanceAdapter (Pipeline.Handle);
switch (key.Key) {
case ConsoleKey.C:
UpdateColorChannel ("CONTRAST", key.Modifiers == ConsoleModifiers.Shift, cb);
break;
case ConsoleKey.B:
UpdateColorChannel ("BRIGHTNESS", key.Modifiers == ConsoleModifiers.Shift, cb);
break;
case ConsoleKey.H:
UpdateColorChannel ("HUE", key.Modifiers == ConsoleModifiers.Shift, cb);
break;
case ConsoleKey.S:
UpdateColorChannel ("SATURATION", key.Modifiers == ConsoleModifiers.Shift, cb);
break;
case ConsoleKey.Q:
MainLoop.Quit ();
break;
}
PrintCurrentValues ();
}
return true;
}
// Output the current values of all Color Balance channels
static void PrintCurrentValues () {
// Output Color Balance value
var cb = new Gst.Video.ColorBalanceAdapter (Pipeline.Handle);
var channels = cb.ListChannels ();
foreach (var ch in channels) {
var value = cb.GetValue (ch);
Console.WriteLine ("{0}: {1}", ch.Label, 100 * (value - ch.MinValue) / (ch.MaxValue - ch.MinValue));
}
Console.WriteLine ();
}
public static void Main (string[] args)
{
// Initialize GStreamer
Application.Init (ref args);
GtkSharp.GstreamerSharp.ObjectManager.Initialize ();
// Print usage map
Console.WriteLine ("USAGE: Choose one of the following options, then press enter:");
Console.WriteLine (" 'C' to increase contrast, 'c' to decrease contrast");
Console.WriteLine (" 'B' to increase brightness, 'b' to decrease brightness");
Console.WriteLine (" 'H' to increase hue, 'h' to decrease hue");
Console.WriteLine (" 'S' to increase saturation, 's' to decrease saturation");
Console.WriteLine (" 'Q' to quit");
// Build the pipeline
Pipeline = Parse.Launch ("playbin uri=http://freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm");
// Add a keyboard watch so we get notified of keystrokes
// Start playing
var ret = Pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
PrintCurrentValues ();
// Create a GLib Main Loop and set it to run
MainLoop = new GLib.MainLoop ();
GLib.Timeout.Add (50, HandleKeyboard);
MainLoop.Run ();
// Free resources
Pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,91 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
using System.Text;
namespace GstreamerSharp
{
class Playback
{
const uint PlayFlagsVis = (1 << 3);
static Element Pipeline;
// Return TRUE if this is a Visualization element
static bool FilterVisFeatures (PluginFeature feature) {
if (!(feature is ElementFactory))
return false;
var factory = (ElementFactory)feature;
if (!factory.GetMetadata (Gst.Constants.ELEMENT_METADATA_KLASS).Contains ("Visualization"))
return false;
return true;
}
public static void Main (string[] args)
{
ElementFactory selectedFactory = null;
// Initialize GStreamer
Application.Init (ref args);
// Get a list of all visualization plugins
var list = Registry.Get().FeatureFilter (FilterVisFeatures, false);
// Print their names
Console.WriteLine ("Available visualization plugins:");
foreach (var walk in list) {
var factory = (ElementFactory)walk;
var name = factory.Name;
Console.WriteLine(" {0}", name);
if (selectedFactory == null && name.StartsWith ("goom")) {
selectedFactory = factory;
}
}
// Don't use the factory if it's still empty
// e.g. no visualization plugins found
if (selectedFactory == null) {
Console.WriteLine ("No visualization plugins found!");
return;
}
// We have now selected a factory for the visualization element
Console.WriteLine ("Selected '{0}'", selectedFactory.Name);
var visPlugin = selectedFactory.Create ();
if (visPlugin == null)
return;
// Build the pipeline
Pipeline = Parse.Launch ("playbin uri=http://1live.akacast.akamaistream.net/7/706/119434/v1/gnl.akacast.akamaistream.net/1live");
// Set the visualization flag
var flags = (uint)Pipeline ["flags"];
flags |= PlayFlagsVis;
Pipeline ["flags"] = flags;
// set vis plugin for playbin
Pipeline ["vis-plugin"] = visPlugin;
// Start playing
var ret = Pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
// Wait until error or EOS
var bus = Pipeline.Bus;
var msg = bus.TimedPopFiltered (Constants.CLOCK_TIME_NONE, MessageType.Error | MessageType.Eos);
// Free resources
Pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,61 @@
// Authors
// Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
using System;
using Gst;
using System.Runtime.InteropServices;
using System.Text;
namespace GstreamerSharp
{
class Playback
{
public static void Main (string[] args)
{
// Initialize GStreamer
Application.Init (ref args);
// Build the pipeline
var pipeline = Parse.Launch ("playbin uri=http://freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm");
// Create the elements inside the sink bin
var equalizer = ElementFactory.Make ("equalizer-3bands", "equalizer");
var convert = ElementFactory.Make ("audioconvert", "convert");
var sink = ElementFactory.Make ("autoaudiosink", "audio_sink");
if (equalizer == null || convert == null || sink == null) {
Console.WriteLine ("Not all elements could be created.");
return;
}
// Create the sink bin, add the elements and link them
var bin = new Bin ("audio_sink_bin");
bin.Add (equalizer, convert, sink);
Element.Link (equalizer, convert, sink);
var pad = equalizer.GetStaticPad ("sink");
var ghostPad = new GhostPad ("sink", pad);
ghostPad.SetActive (true);
bin.AddPad (ghostPad);
// Configure the equalizer
equalizer["band1"] = (double)-24.0;
equalizer["band2"] = (double)-24.0;
// Set playbin's audio sink to be our sink bin
pipeline["audio-sink"] = bin;
// Start playing
var ret = pipeline.SetState (State.Playing);
if (ret == StateChangeReturn.Failure) {
Console.WriteLine ("Unable to set the pipeline to the playing state.");
return;
}
// Wait until error or EOS
var bus = pipeline.Bus;
var msg = bus.TimedPopFiltered (Constants.CLOCK_TIME_NONE, MessageType.Error | MessageType.Eos);
// Free resources
pipeline.SetState (State.Null);
}
}
}
@@ -0,0 +1,274 @@
// 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;
IntPtr _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 = 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.Global.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, Gst.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 IntPtr gdk_x11_window_get_xid (IntPtr handle);
[DllImport ("gdk-win32-3.0-0.dll") ]
static extern IntPtr gdk_win32_drawable_get_handle (IntPtr handle);
[DllImport ("libX11.so.6")]
static extern int XInitThreads ();
}
}
@@ -0,0 +1,42 @@
examples = [
['playback', 'Playback.cs'],
['video-overlay' , 'VideoOverlay.cs', has_gtk, gtk_sharp_dep],
['basic-tutorial-1' , 'BasicTutorial1.cs',],
['basic-tutorial-2' , 'BasicTutorial2.cs',],
['basic-tutorial-3' , 'BasicTutorial3.cs',],
['basic-tutorial-4' , 'BasicTutorial4.cs',],
['basic-tutorial-5' , 'BasicTutorial5.cs', has_gtk, gtk_sharp_dep],
['basic-tutorial-6' , 'BasicTutorial6.cs',],
['basic-tutorial-7' , 'BasicTutorial7.cs',],
['basic-tutorial-8' , 'BasicTutorial8.cs',],
['basic-tutorial-9' , 'BasicTutorial9.cs',],
['basic-tutorial-12' , 'BasicTutorial12.cs',],
['basic-tutorial-13' , 'BasicTutorial13.cs',],
['example-volume' , 'ExampleVolume.cs',],
['playback-tutorial-1' , 'PlaybackTutorial1.cs',],
['playback-tutorial-2' , 'PlaybackTutorial2.cs',],
['playback-tutorial-3' , 'PlaybackTutorial3.cs',],
['playback-tutorial-4' , 'PlaybackTutorial4.cs',],
['playback-tutorial-5' , 'PlaybackTutorial5.cs',],
['playback-tutorial-6' , 'PlaybackTutorial6.cs',],
['playback-tutorial-7' , 'PlaybackTutorial7.cs',],
]
foreach example: examples
deps = [gst_sharp_dep]
if example.length() == 2 or example.get(2)
if example.length() > 2
deps += example.get(3)
endif
executable(example.get(0), example.get(1),
cs_args: ['-unsafe'], dependencies: deps)
endif
endforeach
if ges_dep.found()
executable('ges-example', 'GESExample.cs',
cs_args: ['-unsafe'],
dependencies: [gst_sharp_dep],
link_with: ges_sharp)
endif