Alternative to BufferedStream in UWP - c#

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?

Related

How do I avoid timeout when using BinaryReader and BinaryWriter on the same CryptoStream?

I have a program that uses BinaryReader and BinaryWriter to send string, int and byte[] messages over the network.
The order and content of the messages is significant for the flow of the execution on both server and client, but the duration is never long.
Now I'm trying to encrypt everything.
This is the new wrapper that I have around the actual code:
using encReaderStream = CryptoStream(clientStream, myAES.CreateDecryptor(), CryptoStreamMode.Read),\
encWriterStream = CryptoStream(clientStream, myAES.CreateEncryptor(), CryptoStreamMode.Write),\
enc_reader = BinaryReader(encReaderStream),\
enc_writer = BinaryWriter(encWriterStream):
....
This example is boo code, but it should be intuitively equivalent to C# in this instance.
What happens now is that the server gets the first encrypted message correctly with enc_reader.ReadString(), and answers with enc_writer.Write("Accepted"). But the client never gets the answer.
I have tested if the order of the messages is significant, and it is. If I instead start by sending a string from the server, then the client gets it, but if I continue to send messages, I will soon get into the same situation.
I have some idea that CryptoStream might be responsible for not cooperating properly with BinaryReader/BinaryWriter, but I don't know how to sort out this mess in a good way.
My server has a lot of functions that just expects a BinaryReader and a BinaryWriter, and it would be super convenient if they could work like before.
EDIT:
I've also replicated the situation in a small C# project here, using the the mentioned implementation of AES with CTR mode.
You can't flush a block cipher in the middle of a block because those bytes are not ready from an algorithmic standpoint. They are not determined.
Probably, the best fix is to use a stream cipher. .NET has poor built-in support for that. Pull in a library that implements AES in counter mode.
Be aware that without using authenticated encryption (and it does not look like you are going it) attackers can edit the data although they cannot read it. Use AES-GCM to mitigate.
Later we found out that the CTR mode library you are using is broken. Use this:
public int InputBlockSize { get { return 1; } }
public int OutputBlockSize { get { return 1; } }

C# best way to implement TCP Client Server Application

I want to extend my experience with the .NET framework and want to build a client/server application.
Actually, the client/server is a small Point Of Sale system but first, I want to focus on the communication between server and client.
In the future, I want to make it a WPF application but for now, I simply started with a console application.
2 functionalities:
client(s) receive(s) a dataset and every 15/30min an update with changed prices/new products
(So the code will be in a Async method with a Thread.sleep for 15/30 mins).
when closing the client application, sending a kind of a report (for example, an xml)
On the internet, I found lots of examples but i can't decide which one is the best/safest/performanced manner of working so i need some advice for which techniques i should implement.
CLIENT/SERVER
I want 1 server application that handles max 6 clients. I read that threads use a lot of mb and maybe a better way will be tasks with async/await functionallity.
Example with ASYNC/AWAIT
http://bsmadhu.wordpress.com/2012/09/29/simplify-asynchronous-programming-with-c-5-asyncawait/
Example with THREADS
mikeadev.net/2012/07/multi-threaded-tcp-server-in-csharp/
Example with SOCKETS
codereview.stackexchange.com/questions/5306/tcp-socket-server
This seems to be a great example of sockets, however, the revisioned code isn't working completely because not all the classes are included
msdn.microsoft.com/en-us/library/fx6588te(v=vs.110).aspx
This example of MSDN has a lot more with Buffersize and a signal for the end of a message. I don't know if this just an "old way" to do this because in my previous examples, they just send a string from the client to the server and that's it.
.NET FRAMEWORK REMOTING/ WCF
I found also something about the remoting part of .NET and WCF but don' know if I need to implement this because i think the example with Async/Await isn't bad.
SERIALIZED OBJECTS / DATASET / XML
What is the best way to send data between it? Juse an XML serializer or just binary?
Example with Dataset -> XML
stackoverflow.com/questions/8384014/convert-dataset-to-xml
Example with Remoting
akadia.com/services/dotnet_dataset_remoting.html
If I should use the Async/Await method, is it right to something like this in the serverapplication:
while(true)
{
string input = Console.ReadLine();
if(input == "products")
SendProductToClients(port);
if(input == "rapport")
{
string Example = Console.ReadLine();
}
}
Here are several things anyone writing a client/server application should consider:
Application layer packets may span multiple TCP packets.
Multiple application layer packets may be contained within a single TCP packet.
Encryption.
Authentication.
Lost and unresponsive clients.
Data serialization format.
Thread based or asynchronous socket readers.
Retrieving packets properly requires a wrapper protocol around your data. The protocol can be very simple. For example, it may be as simple as an integer that specifies the payload length. The snippet I have provided below was taken directly from the open source client/server application framework project DotNetOpenServer available on GitHub. Note this code is used by both the client and the server:
private byte[] buffer = new byte[8192];
private int payloadLength;
private int payloadPosition;
private MemoryStream packet = new MemoryStream();
private PacketReadTypes readState;
private Stream stream;
private void ReadCallback(IAsyncResult ar)
{
try
{
int available = stream.EndRead(ar);
int position = 0;
while (available > 0)
{
int lengthToRead;
if (readState == PacketReadTypes.Header)
{
lengthToRead = (int)packet.Position + available >= SessionLayerProtocol.HEADER_LENGTH ?
SessionLayerProtocol.HEADER_LENGTH - (int)packet.Position :
available;
packet.Write(buffer, position, lengthToRead);
position += lengthToRead;
available -= lengthToRead;
if (packet.Position >= SessionLayerProtocol.HEADER_LENGTH)
readState = PacketReadTypes.HeaderComplete;
}
if (readState == PacketReadTypes.HeaderComplete)
{
packet.Seek(0, SeekOrigin.Begin);
BinaryReader br = new BinaryReader(packet, Encoding.UTF8);
ushort protocolId = br.ReadUInt16();
if (protocolId != SessionLayerProtocol.PROTOCAL_IDENTIFIER)
throw new Exception(ErrorTypes.INVALID_PROTOCOL);
payloadLength = br.ReadInt32();
readState = PacketReadTypes.Payload;
}
if (readState == PacketReadTypes.Payload)
{
lengthToRead = available >= payloadLength - payloadPosition ?
payloadLength - payloadPosition :
available;
packet.Write(buffer, position, lengthToRead);
position += lengthToRead;
available -= lengthToRead;
payloadPosition += lengthToRead;
if (packet.Position >= SessionLayerProtocol.HEADER_LENGTH + payloadLength)
{
if (Logger.LogPackets)
Log(Level.Debug, "RECV: " + ToHexString(packet.ToArray(), 0, (int)packet.Length));
MemoryStream handlerMS = new MemoryStream(packet.ToArray());
handlerMS.Seek(SessionLayerProtocol.HEADER_LENGTH, SeekOrigin.Begin);
BinaryReader br = new BinaryReader(handlerMS, Encoding.UTF8);
if (!ThreadPool.QueueUserWorkItem(OnPacketReceivedThreadPoolCallback, br))
throw new Exception(ErrorTypes.NO_MORE_THREADS_AVAILABLE);
Reset();
}
}
}
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), null);
}
catch (ObjectDisposedException)
{
Close();
}
catch (Exception ex)
{
ConnectionLost(ex);
}
}
private void Reset()
{
readState = PacketReadTypes.Header;
packet = new MemoryStream();
payloadLength = 0;
payloadPosition = 0;
}
If you're transmitting point of sale information, it should be encrypted. I suggest TLS which is easily enabled on through .Net. The code is very simple and there are quite a few samples out there so for brevity I'm not going to show it here. If you are interested, you can find an example implementation in DotNetOpenServer.
All connections should be authenticated. There are many ways to accomplish this. I've use Windows Authentication (NTLM) as well as Basic. Although NTLM is powerful as well as automatic it is limited to specific platforms. Basic authentication simply passes a username and password after the socket has been encrypted. Basic authentication can still, however; authenticate the username/password combination against the local server or domain controller essentially impersonating NTLM. The latter method enables developers to easily create non-Windows client applications that run on iOS, Mac, Unix/Linux flavors as well as Java platforms (although some Java implementations support NTLM). Your server implementation should never allow application data to be transferred until after the session has been authenticated.
There are only a few things we can count on: taxes, networks failing and client applications hanging. It's just the nature of things. Your server should implement a method to clean up both lost and hung client sessions. I've accomplished this in many client/server frameworks through a keep-alive (AKA heartbeat) protocol. On the server side I implement a timer that is reset every time a client sends a packet, any packet. If the server doesn't receive a packet within the timeout, the session is closed. The keep-alive protocol is used to send packets when other application layer protocols are idle. Since your application only sends XML once every 15 minutes sending a keep-alive packet once a minute would able the server side to issue an alert to the administrator when a connection is lost prior to the 15 minute interval possibly enabling the IT department to resolve a network issue in a more timely fashion.
Next, data format. In your case XML is great. XML enables you to change up the payload however you want whenever you want. If you really need speed, then binary will always trump the bloated nature of string represented data.
Finally, as #NSFW already stated, threads or asynchronous doesn't really matter in your case. I've written servers that scale to 10000 connections based on threads as well as asynchronous callbacks. It's all really the same thing when it comes down to it. As #NSFW said, most of us are using asynchronous callbacks now and the latest server implementation I've written follows that model as well.
Threads are not terribly expensive, considering the amount of RAM available on modern systems, so I don't think it's helpful to optimize for a low thread count. Especially if we're talking about a difference between 1 thread and 2-5 threads. (With hundreds or thousands of threads, the cost of a thread starts to matter.)
But you do want to optimize for minimal blocking of whatever threads you do have. So for example instead of using Thread.Sleep to do work on 15 minute intervals, just set a timer, let the thread return, and trust the system to invoke your code 15 minutes later. And instead of blocking operations for reading or writing information over the network, use non-blocking operations.
The async/await pattern is the new hotness for asynchronous programming on .Net, and it is a big improvement over the Begin/End pattern that dates back to .Net 1.0. Code written with async/await is still using threads, it is just using features of C# and .Net to hide a lot of the complexity of threads from you - and for the most part, it hides the stuff that should be hidden, so that you can focus your attention on your application's features rather than the details of multi-threaded programming.
So my advice is to use the async/await approach for all of your IO (network and disk) and use timers for periodic chores like sending those updates you mentioned.
And about serialization...
One of the biggest advantages of XML over binary formats is that you can save your XML transmissions to disk and open them up using readily-available tools to confirm that the payload really contains the data that you thought would be in there. So I tend to avoid binary formats unless bandwidth is scarce - and even then, it's useful to develop most of the app using a text-friendly format like XML, and then switch to binary after the basic mechanism of sending and receiving data have been fleshed out.
So my vote is for XML.
And regarding your code example, well ther's no async/await in it...
But first, note that a typical simple TCP server will have a small loop that listens for incoming connections and starts a thread to hanadle each new connection. The code for the connection thread will then listen for incoming data, process it, and send an appropriate response. So the listen-for-new-connections code and the handle-a-single-connection code are completely separate.
So anyway, the connection thread code might look similar to what you wrote, but instead of just calling ReadLine you'd do something like "string line = await ReadLine();" The await keyword is approximately where your code lets one thread exit (after invoking ReadLine) and then resumes on another thread (when the result of ReadLine is available). Except that awaitable methods should have a name that ends with Async, for example ReadLineAsync. Reading a line of text from the network is not a bad idea, but you'll have to write ReadLineAsync yourself, building upon the existing network API.
I hope this helps.

Streaming data between C# applications

I'm trying to share data between two applications: the first gets the data continuously from a sensor, all I need to do is to transmit these data while I'm receiving them to another (WPF) application (and draw a graph).
The data is received through an EventHandler, and then it's transmitted through a socket, like this:
static TcpClient client = new TcpClient("localhost", 8181);
static double w, dba;
static void Write()
{
try
{
Stream s = client.GetStream();
StreamReader sr = new StreamReader(s);
StreamWriter sw = new StreamWriter(s);
sw.AutoFlush = true;
while (true)
{
String line = "W:" + w + "DB/A:" + dba;
sw.Write(line);
Console.WriteLine(sr.ReadLine());
}
s.Close();
}
finally
{
client.Close();
}
}
The thing is, do I need to put it in a separate Thread? (As I tried to, unsuccessfully) Because like this, while the eventHandler keeps being triggered and producing data (storing it into the two variables), the sw seems unable to proceed.
Sorry if the question is a bit vague, it's my first attempt with a distributed app so I'm a bit confused as well.. any advice or help would be very appreciated!
TIA
Use memory mapped files, which allows you to directly share memory between applications. It will be significantly faster than most other approaches.
Look at the section called Non-Persisted Memory-Mapped Files, which details how to share a segment of memory via a string name. I use this in an application I worked on for debugging purposes, and it's fast enough that my C# application could read my native application's memory in real-time.
If you're transmitting the data via this method, consider how you would transmit data in general. Determine a polling frequency (say every 100ms) and have application A write the data to the memory-mapped file. Then have application B read that memory mapped file and store it locally in a collection. This is your transmission.
So A basically writes and rewrites the same structure into the memory mapped file and B reads it at a given polling rate and stores what it polls in a collection.
If both apps are .net, why not use WCF for inter process communication : much more robust than using files. See this link WCF Basic Interprocess Communication

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.

Using FFmpeg in .net?

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.

Categories

Resources