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:
parent
9b9a8546a5
commit
d964558856
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue