Using FFmpeg in .net? - c#

So I know its a fairly big challenge but I want to write a basic movie player/converter in c# using the FFmpeg library. However, the first obstacle I need to overcome is wrapping the FFmpeg library in c#. I've downloaded ffmpeg but couldn't compile it on Windows, so I downloaded a precompiled version for me. Ok awesome. Then I started looking for C# wrappers.
I have looked around and have found a few wrappers such as SharpFFmpeg (http://sourceforge.net/projects/sharpffmpeg/) and ffmpeg-sharp (http://code.google.com/p/ffmpeg-sharp/). First of all, I wanted to use ffmpeg-sharp as its LGPL and SharpFFmpeg is GPL. However, it had quite a few compile errors. Turns out it was written for the mono compiler, I tried compiling it with mono but couldn't figure out how. I then started to manually fix the compiler errors myself, but came across a few scary ones and thought I'd better leave those alone. So I gave up on ffmpeg-sharp.
Then I looked at SharpFFmpeg and it looks like what I want, all the functions P/Invoked for me. However its GPL? Both the AVCodec.cs and AVFormat.cs files look like ports of avcodec.c and avformat.c which I reckon I could port myself? Then not have to worry about licencing.
But I want to get this right before I go ahead and start coding. Should I:
Write my own C++ library for interacting with ffmpeg, then have my C# program talk to the C++ library in order to play/convert videos etc.
OR
Port avcodec.h and avformat.h (is that all i need?) to c# by using a whole lot of DllImports and write it entirely in C#?
First of all consider that I'm not great at C++ as I rarely use it but I know enough to get around. The reason I'm thinking #1 might be the better option is that most FFmpeg tutorials are in C++ and I'd also have more control over memory management than if I was to do it in c#.
What do you think?
Also would you happen to have any useful links (perhaps a tutorial) for using FFmpeg?

The original question is now more than 5 years old. In the meantime there is now a solution for a WinRT solution from ffmpeg and an integration sample from Microsoft.

a few other managed wrappers for you to check out
FFMpeg.NET
FFMpeg-Sharp
Writing your own interop wrappers can be a time-consuming and difficult process in .NET. There are some advantages to writing a C++ library for the interop - particularly as it allows you to greatly simplify the interface that the C# code. However, if you are only needing a subset of the library, it might make your life easier to just do the interop in C#.

You can use this nuget package:
Install-Package Xabe.FFmpeg
I'm trying to make easy to use, cross-platform FFmpeg wrapper.
You can find more information about this at Xabe.FFmpeg
More info in documentation
Conversion is simple:
var conversion = await FFmpeg.Conversions.FromSnippet.ToMp4(Resources.MkvWithAudio, output);
await conversion.Start();

GPL-compiled ffmpeg can be used from non-GPL program (commercial project) only if it is invoked in the separate process as command line utility; all wrappers that are linked with ffmpeg library (including Microsoft's FFMpegInterop) can use only LGPL build of ffmpeg.
You may try my .NET wrapper for FFMpeg: Video Converter for .NET (I'm an author of this library). It embeds FFMpeg.exe into the DLL for easy deployment and doesn't break GPL rules (FFMpeg is NOT linked and wrapper invokes it in the separate process with System.Diagnostics.Process).

A solution that is viable for both Linux and Windows is to just get used to using console ffmpeg in your code. I stack up threads, write a simple thread controller class, then you can easily make use of what ever functionality of ffmpeg you want to use.
As an example, this contains sections use ffmpeg to create a thumbnail from a time that I specify.
In the thread controller you have something like
List<ThrdFfmpeg> threads = new List<ThrdFfmpeg>();
Which is the list of threads that you are running, I make use of a timer to Pole these threads, you can also set up an event if Pole'ing is not suitable for your application.
In this case thw class Thrdffmpeg contains,
public class ThrdFfmpeg
{
public FfmpegStuff ffm { get; set; }
public Thread thrd { get; set; }
}
FFmpegStuff contains the various ffmpeg functionality, thrd is obviously the thread.
A property in FfmpegStuff is the class FilesToProcess, which is used to pass information to the called process, and receive information once the thread has stopped.
public class FileToProcess
{
public int videoID { get; set; }
public string fname { get; set; }
public int durationSeconds { get; set; }
public List<string> imgFiles { get; set; }
}
VideoID (I use a database) tells the threaded process which video to use taken from the database.
fname is used in other parts of my functions that use FilesToProcess, but not used here.
durationSeconds - is filled in by the threads that just collect video duration.
imgFiles is used to return any thumbnails that were created.
I do not want to get bogged down in my code when the purpose of this is to encourage the use of ffmpeg in easily controlled threads.
Now we have our pieces we can add to our threads list, so in our controller we do something like,
AddThread()
{
ThrdFfmpeg thrd;
FileToProcess ftp;
foreach(FileToProcess ff in `dbhelper.GetFileNames(txtCategory.Text))`
{
//make a thread for each
ftp = new FileToProcess();
ftp = ff;
ftp.imgFiles = new List<string>();
thrd = new ThrdFfmpeg();
thrd.ffm = new FfmpegStuff();
thrd.ffm.filetoprocess = ftp;
thrd.thrd = new `System.Threading.Thread(thrd.ffm.CollectVideoLength);`
threads.Add(thrd);
}
if(timerNotStarted)
StartThreadTimer();
}
Now Pole'ing our threads becomes a simple task,
private void timerThreads_Tick(object sender, EventArgs e)
{
int runningCount = 0;
int finishedThreads = 0;
foreach(ThrdFfmpeg thrd in threads)
{
switch (thrd.thrd.ThreadState)
{
case System.Threading.ThreadState.Running:
++runningCount;
//Note that you can still view data progress here,
//but remember that you must use your safety checks
//here more than anywhere else in your code, make sure the data
//is readable and of the right sort, before you read it.
break;
case System.Threading.ThreadState.StopRequested:
break;
case System.Threading.ThreadState.SuspendRequested:
break;
case System.Threading.ThreadState.Background:
break;
case System.Threading.ThreadState.Unstarted:
//Any threads that have been added but not yet started, start now
thrd.thrd.Start();
++runningCount;
break;
case System.Threading.ThreadState.Stopped:
++finishedThreads;
//You can now safely read the results, in this case the
//data contained in FilesToProcess
//Such as
ThumbnailsReadyEvent( thrd.ffm );
break;
case System.Threading.ThreadState.WaitSleepJoin:
break;
case System.Threading.ThreadState.Suspended:
break;
case System.Threading.ThreadState.AbortRequested:
break;
case System.Threading.ThreadState.Aborted:
break;
default:
break;
}
}
if(flash)
{//just a simple indicator so that I can see
//that at least one thread is still running
lbThreadStatus.BackColor = Color.White;
flash = false;
}
else
{
lbThreadStatus.BackColor = this.BackColor;
flash = true;
}
if(finishedThreads >= threads.Count())
{
StopThreadTimer();
ShowSample();
MakeJoinedThumb();
}
}
Putting your own events onto into the controller class works well, but in video work, when my own code is not actually doing any of the video file processing, poling then invoking an event in the controlling class works just as well.
Using this method I have slowly built up just about every video and stills function I think I will ever use, all contained in the one class, and that class as a text file is useable on the Lunux and Windows version, with just a small number of pre-process directives.

Related

Alternative to BufferedStream in UWP

I'm targeting an IoT core device that I'm hoping to run a UWP application on. The project is primarily to process a motion JPEG stream, but in setting up that stream I've found that System.IO doesn't seem to contain a definition for 'BufferedStream'.
I wanted to wrap a 'BinaryReader' around a 'BufferedStream', because I need to both minimise the number of IO reads on the transport, as well as tell the 'BinaryReader' to read and return a given number of bytes. Reading directly doesn't always return all the bytes, which is problematic when I'm subsequently processing the image looking for certain elements.
public class MultiPartStream
{
public MultiPartStream(Stream multipartStream)
{
_reader = new BinaryReader(new BufferedStream(multipartStream));
}
What's my alternative here? There's an old thread purporting to have added support for 'BufferedStream' to .NET core, so where is it?

GStreamer# equivalent for video overlay functions

I have a C#/Mono application for rendering video streams and, until recently, I've been using my own in-house developed InterOp bindings.
I'm now moving from that method to use those of GStreamer#, since that's likely to be much less maintenance effort, at least for me :-)
Since I need to bind independent video streams to a specific DrawableArea widgets, my method captured the GStreamer messages then checked them with the function gst_is_video_overlay_prepare_window_handle_message(msg)(a).
If that returned true, I then responded with a call to gst_video_overlay_set_window_handle(xid), where xid was the handle for the widget obtained earlier with gdk_x11_window_get_xid().
My problem is this: searching through the GStreamer# code, I cannot find an equivalent function for doing the binding so I was wondering how this is meant to be done.
Anyone have any advice or information to offer?
The source code for those two functions are in gst-plugins-base-1.4.4/gst-libs/gst/video/videooverlay.c so, in a pinch, I could dummy up my own functions to do the job (or just stick with our bindings for that one little bit) but it seems to me this would have been included in GStreamer# since rendering to specific widgets seems like a very handy facility.
(a) Those GStreamer wags. They must replace their keyboards quite a bit with all that unnecessary typing :-)
Turns out those functions are available, but in a separate library and sub-namespace to the baseline GStreamer stuff.
The getting of the Xid is still done with a self-made InterOp binding, to wit:
[DllImport("libgdk-3", EntryPoint = "gdk_x11_window_get_xid")]
private extern static IntPtr GdkX11WindowGetXid(IntPtr window);
You also have instance-level variables for the playbin, bus and X11 window ID:
private IntPtr windowXid;
private Gst.Element playBin;
private Gst.Bus bus;
Then, when instantiating the class, you capture the Realized signal and ensure that all messages on the GStreamer bus go to your callback function:
this.Realized += OnRealized;
playBin = Gst.ElementFactory.Make('playbin', 'playbin');
bus = playBin.Bus;
bus.AddSignalWatch();
bus.Message += MessageCallback;
In that realisation function, you save the Xid for later use (in an instance variable):
void OnRealized(object o, EventArgs args) {
windowXid = GdkX11WindowGetXid(this.Window.Handle);
}
and, when asked by GStreamer, provide this handle in response to the request:
private void MessageCallback(object o, MessageArgs args) {
Gst.Message msg = args.Message;
if (! Gst.Video.Global.IsVideoOverlayPrepareWindowHandleMessage(msg))
return;
Gst.Element src = msg.Src as Gst.Element;
if (src == null)
return;
Gst.Element overlay = null;
if (src is Gst.Bin)
overlay = ((Gst.Bin)src).GetByInterface
Gst.Video.VideoOverlayAdapter = new Gst.Video.VideoOverlayAdapter(overlay.Handle);
adapter.WindowHandle = windowXid;
}
Note that I've fully qualified all the GStreamer objects so it's absolutely clear where they can be found. The code would probably be a lot cleaner without them (and with using var for the variables) but I wanted to ensure all information was available.

Live video encoding using ffmpeg or expression encoder [duplicate]

So I know its a fairly big challenge but I want to write a basic movie player/converter in c# using the FFmpeg library. However, the first obstacle I need to overcome is wrapping the FFmpeg library in c#. I've downloaded ffmpeg but couldn't compile it on Windows, so I downloaded a precompiled version for me. Ok awesome. Then I started looking for C# wrappers.
I have looked around and have found a few wrappers such as SharpFFmpeg (http://sourceforge.net/projects/sharpffmpeg/) and ffmpeg-sharp (http://code.google.com/p/ffmpeg-sharp/). First of all, I wanted to use ffmpeg-sharp as its LGPL and SharpFFmpeg is GPL. However, it had quite a few compile errors. Turns out it was written for the mono compiler, I tried compiling it with mono but couldn't figure out how. I then started to manually fix the compiler errors myself, but came across a few scary ones and thought I'd better leave those alone. So I gave up on ffmpeg-sharp.
Then I looked at SharpFFmpeg and it looks like what I want, all the functions P/Invoked for me. However its GPL? Both the AVCodec.cs and AVFormat.cs files look like ports of avcodec.c and avformat.c which I reckon I could port myself? Then not have to worry about licencing.
But I want to get this right before I go ahead and start coding. Should I:
Write my own C++ library for interacting with ffmpeg, then have my C# program talk to the C++ library in order to play/convert videos etc.
OR
Port avcodec.h and avformat.h (is that all i need?) to c# by using a whole lot of DllImports and write it entirely in C#?
First of all consider that I'm not great at C++ as I rarely use it but I know enough to get around. The reason I'm thinking #1 might be the better option is that most FFmpeg tutorials are in C++ and I'd also have more control over memory management than if I was to do it in c#.
What do you think?
Also would you happen to have any useful links (perhaps a tutorial) for using FFmpeg?
The original question is now more than 5 years old. In the meantime there is now a solution for a WinRT solution from ffmpeg and an integration sample from Microsoft.
a few other managed wrappers for you to check out
FFMpeg.NET
FFMpeg-Sharp
Writing your own interop wrappers can be a time-consuming and difficult process in .NET. There are some advantages to writing a C++ library for the interop - particularly as it allows you to greatly simplify the interface that the C# code. However, if you are only needing a subset of the library, it might make your life easier to just do the interop in C#.
You can use this nuget package:
Install-Package Xabe.FFmpeg
I'm trying to make easy to use, cross-platform FFmpeg wrapper.
You can find more information about this at Xabe.FFmpeg
More info in documentation
Conversion is simple:
var conversion = await FFmpeg.Conversions.FromSnippet.ToMp4(Resources.MkvWithAudio, output);
await conversion.Start();
GPL-compiled ffmpeg can be used from non-GPL program (commercial project) only if it is invoked in the separate process as command line utility; all wrappers that are linked with ffmpeg library (including Microsoft's FFMpegInterop) can use only LGPL build of ffmpeg.
You may try my .NET wrapper for FFMpeg: Video Converter for .NET (I'm an author of this library). It embeds FFMpeg.exe into the DLL for easy deployment and doesn't break GPL rules (FFMpeg is NOT linked and wrapper invokes it in the separate process with System.Diagnostics.Process).
A solution that is viable for both Linux and Windows is to just get used to using console ffmpeg in your code. I stack up threads, write a simple thread controller class, then you can easily make use of what ever functionality of ffmpeg you want to use.
As an example, this contains sections use ffmpeg to create a thumbnail from a time that I specify.
In the thread controller you have something like
List<ThrdFfmpeg> threads = new List<ThrdFfmpeg>();
Which is the list of threads that you are running, I make use of a timer to Pole these threads, you can also set up an event if Pole'ing is not suitable for your application.
In this case thw class Thrdffmpeg contains,
public class ThrdFfmpeg
{
public FfmpegStuff ffm { get; set; }
public Thread thrd { get; set; }
}
FFmpegStuff contains the various ffmpeg functionality, thrd is obviously the thread.
A property in FfmpegStuff is the class FilesToProcess, which is used to pass information to the called process, and receive information once the thread has stopped.
public class FileToProcess
{
public int videoID { get; set; }
public string fname { get; set; }
public int durationSeconds { get; set; }
public List<string> imgFiles { get; set; }
}
VideoID (I use a database) tells the threaded process which video to use taken from the database.
fname is used in other parts of my functions that use FilesToProcess, but not used here.
durationSeconds - is filled in by the threads that just collect video duration.
imgFiles is used to return any thumbnails that were created.
I do not want to get bogged down in my code when the purpose of this is to encourage the use of ffmpeg in easily controlled threads.
Now we have our pieces we can add to our threads list, so in our controller we do something like,
AddThread()
{
ThrdFfmpeg thrd;
FileToProcess ftp;
foreach(FileToProcess ff in `dbhelper.GetFileNames(txtCategory.Text))`
{
//make a thread for each
ftp = new FileToProcess();
ftp = ff;
ftp.imgFiles = new List<string>();
thrd = new ThrdFfmpeg();
thrd.ffm = new FfmpegStuff();
thrd.ffm.filetoprocess = ftp;
thrd.thrd = new `System.Threading.Thread(thrd.ffm.CollectVideoLength);`
threads.Add(thrd);
}
if(timerNotStarted)
StartThreadTimer();
}
Now Pole'ing our threads becomes a simple task,
private void timerThreads_Tick(object sender, EventArgs e)
{
int runningCount = 0;
int finishedThreads = 0;
foreach(ThrdFfmpeg thrd in threads)
{
switch (thrd.thrd.ThreadState)
{
case System.Threading.ThreadState.Running:
++runningCount;
//Note that you can still view data progress here,
//but remember that you must use your safety checks
//here more than anywhere else in your code, make sure the data
//is readable and of the right sort, before you read it.
break;
case System.Threading.ThreadState.StopRequested:
break;
case System.Threading.ThreadState.SuspendRequested:
break;
case System.Threading.ThreadState.Background:
break;
case System.Threading.ThreadState.Unstarted:
//Any threads that have been added but not yet started, start now
thrd.thrd.Start();
++runningCount;
break;
case System.Threading.ThreadState.Stopped:
++finishedThreads;
//You can now safely read the results, in this case the
//data contained in FilesToProcess
//Such as
ThumbnailsReadyEvent( thrd.ffm );
break;
case System.Threading.ThreadState.WaitSleepJoin:
break;
case System.Threading.ThreadState.Suspended:
break;
case System.Threading.ThreadState.AbortRequested:
break;
case System.Threading.ThreadState.Aborted:
break;
default:
break;
}
}
if(flash)
{//just a simple indicator so that I can see
//that at least one thread is still running
lbThreadStatus.BackColor = Color.White;
flash = false;
}
else
{
lbThreadStatus.BackColor = this.BackColor;
flash = true;
}
if(finishedThreads >= threads.Count())
{
StopThreadTimer();
ShowSample();
MakeJoinedThumb();
}
}
Putting your own events onto into the controller class works well, but in video work, when my own code is not actually doing any of the video file processing, poling then invoking an event in the controlling class works just as well.
Using this method I have slowly built up just about every video and stills function I think I will ever use, all contained in the one class, and that class as a text file is useable on the Lunux and Windows version, with just a small number of pre-process directives.

How Can I Hook a Youtube Video (Flash Player?) To Slow Down Playback?

The only good software I know which can decelerate and accelerate the playback of a YouTube video in any browser without first downloading it (because that would be cumbersome), is Enounce MySpeed.
Unfortunately, this software is not free, and my trial version ran out. I was playing around with its registry settings and noticed a few keys:
ProgramsToHook: iexplore.exe;firefox.exe;plugin-container.exe;chrome.exe;safari.exe;opera.exe;maxthon.exe;feeddemon.exe;realplay.exe;flvplayer.exe;flv player.exe;flock.exe;adobe media player.exe
UseFlashAdapter: 1
LLModules: ole32.dll;nspr4.dll;chrome.exe;realplay.exe;objb3201.dll;oleaut32.dll;rpflashplayer.dll
ModulesToIntercept: flash10*;flash9*;npswf32.dll;gcswf32.dll;fldbg10*;flashplayer.3.1.1k.ocx;adobe media player.exe
Based on the names and values of these registry keys, I'm guessing the MySpeed software hooks some function(s) in the listed modules (but modules are or aren't the same as DLLs?..) and does so for each process listed in ProgramsToHook. This is what I don't understand. What is the concept of the MySpeed software. Obviously it's hooking something, but I'm not too familiar with the intricacies of Windows hooks so I came to ask you experts. I'm thinking if I can understand how this hook process works, I can make my own version of the software using EasyHook, which is a fantastic .NET library to perform user-mode and kernel-mode hooks.
I thought that Windows user-mode hooking goes something like this. You choose one function in one DLL, and you intercept that function (a.k.a hook) in one process you want. If you want to hook the DLL in multiple processes, you just have to repeat the procedure for each process.
And then kernel-mode hooking is just choosing one function in one DLL and intercepting that function in every process that calls it (hence kernel-mode). But surely there are tons of ways to hook; I'm not too sure on whats the difference between these two hooks and DLL injection either.
So the point is, I'd like to know how MySpeed works. What is their hooking concept? If I can know this then I can make such a software in .NET!
Thanks in advance.
I can't provide you with an accurate explanation as I don't know the API calls or capabilites, but it goes something like this:
You app looks for iexplore.exe where it intercepts calls to certain modules. The module is mainly flash player. Flash has support for playing the video slower so you modify the call from iexplore.exe (JavaScript play button on webpage) or make an additional call to set playback speed.
What you need to do:
Use this tool to check what is actually happening: http://www.nektra.com/products/deviare-api-hook-windows/
Learn how to ask Flash Player to slow down a video (probably in Flash API docs). One Simple approach could be to see what MySpeed is actually doing using the Deviare API hook tool.
Write a program that replicates this procedure. It involves intercepting messages sent from one handle (iexplore.exe) to another (flash .dll). This can't be done externally, it has to be done internally, so this may be of help: http://www.codeproject.com/KB/threads/winspy.aspx
On hooks: http://msdn.microsoft.com/en-gb/library/ms644960.aspx
I don't think many people has done this in C#, so it could offer a challenge. I would though be interested in the progress (obstacles) if you have a blog or something to share the gory details on. :)
EDIT: The Deviare API Hook software seems not only to spy on calls, but also allow you to intercept them. So its a all-in-one package for your needs. :)
EDIT2: Relevant question: How do I intercept messages being sent to a window?
The key to speeding up or slowing down a video is to convince multimedia players that your computer is slower or faster than it really is. This can be accomplished hooking timeGetTime().
This is an extremely easy C# code to accomplish it:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Nektra.Deviare2;
namespace DeviareTest
{
public partial class Form1 : Form
{
private int nSpeed;
private uint nTime;
private NktSpyMgr _spyMgr;
public Form1()
{
InitializeComponent();
_spyMgr = new NktSpyMgr();
_spyMgr.Initialize();
_spyMgr.OnFunctionCalled += new DNktSpyMgrEvents_OnFunctionCalledEventHandler(OnFunctionCalled);
}
private void Form1_Load(object sender, EventArgs e)
{
NktHook hook = _spyMgr.CreateHook("WINMM.dll!timeGetTime", (int)(eNktHookFlags.flgOnlyPostCall));
hook.Hook(true);
bool bProcessFound = false;
NktProcessesEnum enumProcess = _spyMgr.Processes();
NktProcess tempProcess = enumProcess.First();
while (tempProcess != null)
{
if (tempProcess.Name.Equals("iexplore.exe", StringComparison.InvariantCultureIgnoreCase) && tempProcess.PlatformBits == 32)
{
hook.Attach(tempProcess, true);
bProcessFound = true;
}
tempProcess = enumProcess.Next();
}
if(!bProcessFound)
{
MessageBox.Show("Please run \"iexplore.exe\" before!", "Error");
Environment.Exit(0);
}
}
private void OnFunctionCalled(NktHook hook, NktProcess process, NktHookCallInfo hookCallInfo)
{
nTime++;
if (nSpeed==-2)
hookCallInfo.Result().LongVal = hookCallInfo.Result().LongVal - (int)(nTime * 0.2);
else if(nSpeed==2)
hookCallInfo.Result().LongVal = hookCallInfo.Result().LongVal + (int)(nTime * 3);
}
private void SlowButton_CheckedChanged(object sender, EventArgs e)
{
nSpeed = -2;
}
private void FastButton_CheckedChanged(object sender, EventArgs e)
{
nSpeed = 2;
}
}
}
I just published an article with a code example showing how to do this with the Deviare hooking engine. The sample code only works with the video part (not audio) and it is available here.
Youtube now has an html5 player with playback speed controls.
All you have to do is enable html5 here http://www.youtube.com/html5
Only some of the videos support the html5 player yet, though.
Hope this helps.
The key to speeding up or slowing down a video is to convince multimedia players that your computer is slower or faster than it really is
manipulating the system time will be a VERY dangerous and idiotic thing to do - not only will you break user-mode threadslices and hence have a serious impact on system-performance but you also will break many logging-functionalities and even user-mode reflectors which control KM-drivers ... this could both crash and physically harm (!) your system because modern hardware is programmable, given the correct (& proprietary, of course) set of func-calls and such. I would highly advise to NOT do reproduce this, even a few AV-apps will intercept this because of its dangerous nature.
But you're somewhat lucky : the kernel uses its own time, synced to hardware so windows itself COULD remain stable for a limited amount of time.
I think you should get back to the drawing-board, manipulating essential structures of your operating-system certainly is not the right way to accomplish your goal.

Blocking functions in XNA

I'm currently coding an RPG engine in XNA. The engine executes a series of scripting commands but has to block until the next scripting command. How can I do this?
For example:
// interact with an NPC named in String 'Name'
String interactfunc = String.Format("{0}_Interact", Name);
System.Reflection.MethodInfo info = Factory.Script.GetType().GetMethod(interactfunc);
if (info != null) info.Invoke(Factory.Script, new object[]{this});
//this may run the following script command for NPC 'Bob'
public void Bob_Interact(NPC Bob)
{
Bob.Say("Well this worked.");
Bob.Say("Didnt it?");
}
//the say command looks like this
public void Say(String Text)
{
TalkGui gui = new TalkGui(this, Text);
Factory.Game.Guis.Add(gui);
Factory.FocusedGui = gui;
}
Now I need the script the wait until the first TalkGui has been dismissed before running the next script command.
What's the best way to do this? Maybe run the script functions in their own thread or something?
You don't want to use threads for this kind of thing. They're far too heavy weight.
What you really want is co-routines. You can emulate these in C# using yield and iterators.
There are some examples here and here. And perhaps my answer here is worth reading too.
C# 5.0 is introducing a much nicer way of doing asynchronous programming like this. Here's a video and here is the CTP.

Categories

Resources