Multithreaded AviWriter.cs

Moves calls to AVIStreamWrite() to a separate worker thread.  They are where all of the cpu time for video compression is used, so can give a decent speedup.  Could conceivably go slower on pathetic single core machines due to synchronization and copy overhead.
This commit is contained in:
goyuken 2012-05-05 14:52:23 +00:00
parent 9b9a8546a5
commit d964558856
1 changed files with 76 additions and 2 deletions

View File

@ -52,6 +52,58 @@ namespace BizHawk.MultiClient
/// </summary>
public void OpenFile(string baseName) { OpenFile(CreateBasicNameProvider(baseName)); }
// thread communication
// synchronized queue with custom messages
// it seems like there are 99999 ways to do everything in C#, so i'm sure this is not the best
System.Collections.Concurrent.BlockingCollection<Object> threadQ;
System.Threading.Thread workerT;
void threadproc()
{
try
{
while (true)
{
Object o = threadQ.Take();
if (o is IVideoProvider)
AddFrameEx((IVideoProvider)o);
else if (o is short[])
AddSamplesEx((short[])o);
else
// anything else is assumed to be quit time
return;
}
}
catch (Exception)
{
return;
}
}
// we can't pass the IVideoProvider we get to another thread, because it doesn't actually keep a local copy of its data,
// instead grabbing it from the emu as needed. this causes frame loss/dupping as a race condition
// instead we pass this
class VideoCopy : IVideoProvider
{
int[] vb;
int bw, bh, bc;
public int BufferWidth { get {return bw;} }
public int BufferHeight { get { return bh; } }
public int BackgroundColor { get { return bc; } }
public VideoCopy(IVideoProvider c)
{
vb = (int []) c.GetVideoBuffer().Clone ();
bw = c.BufferWidth;
bh = c.BufferHeight;
bc = c.BackgroundColor;
}
public int[] GetVideoBuffer()
{
return vb;
}
}
/// <summary>
/// opens an avi file for recording with the supplied enumerator used to name files.
/// set a video codec token first.
@ -62,16 +114,29 @@ namespace BizHawk.MultiClient
this.nameProvider = nameProvider;
if (currVideoCodecToken == null)
throw new InvalidOperationException("Tried to start recording an AVI with no video codec token set");
threadQ = new System.Collections.Concurrent.BlockingCollection<Object>(30);
workerT = new System.Threading.Thread(new System.Threading.ThreadStart(threadproc));
workerT.Start();
}
public void CloseFile()
{
threadQ.Add(new Object ()); // acts as stop message
workerT.Join();
if (currSegment != null)
currSegment.Dispose();
currSegment = null;
}
public void AddFrame(IVideoProvider source)
public void AddFrame(IVideoProvider source)
{
if (!workerT.IsAlive)
// signal some sort of error?
return;
threadQ.Add(new VideoCopy (source));
}
void AddFrameEx(IVideoProvider source)
{
SetVideoParameters(source.BufferWidth, source.BufferHeight);
ConsiderLengthSegment();
@ -79,7 +144,16 @@ namespace BizHawk.MultiClient
currSegment.AddFrame(source);
}
public void AddSamples(short[] samples)
public void AddSamples(short[] samples)
{
if (!workerT.IsAlive)
// signal some sort of error?
return;
// as MainForm.cs is written now, samples is all ours (nothing else will use it for anything)
// but that's a bad assumption to make and could change in the future, so copy it since we're passing to another thread
threadQ.Add((short []) samples.Clone ());
}
void AddSamplesEx(short[] samples)
{
ConsiderLengthSegment();
if (currSegment == null) Segment();