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>
|
/// </summary>
|
||||||
public void OpenFile(string baseName) { OpenFile(CreateBasicNameProvider(baseName)); }
|
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>
|
/// <summary>
|
||||||
/// opens an avi file for recording with the supplied enumerator used to name files.
|
/// opens an avi file for recording with the supplied enumerator used to name files.
|
||||||
/// set a video codec token first.
|
/// set a video codec token first.
|
||||||
|
@ -62,16 +114,29 @@ namespace BizHawk.MultiClient
|
||||||
this.nameProvider = nameProvider;
|
this.nameProvider = nameProvider;
|
||||||
if (currVideoCodecToken == null)
|
if (currVideoCodecToken == null)
|
||||||
throw new InvalidOperationException("Tried to start recording an AVI with no video codec token set");
|
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()
|
public void CloseFile()
|
||||||
{
|
{
|
||||||
|
threadQ.Add(new Object ()); // acts as stop message
|
||||||
|
workerT.Join();
|
||||||
if (currSegment != null)
|
if (currSegment != null)
|
||||||
currSegment.Dispose();
|
currSegment.Dispose();
|
||||||
currSegment = null;
|
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);
|
SetVideoParameters(source.BufferWidth, source.BufferHeight);
|
||||||
ConsiderLengthSegment();
|
ConsiderLengthSegment();
|
||||||
|
@ -79,7 +144,16 @@ namespace BizHawk.MultiClient
|
||||||
currSegment.AddFrame(source);
|
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();
|
ConsiderLengthSegment();
|
||||||
if (currSegment == null) Segment();
|
if (currSegment == null) Segment();
|
||||||
|
|
Loading…
Reference in New Issue