add automated dumping. command line example:

bizhawk.multiclient --dump-type=ffmpeg --dump-name=foobar.avi --dump-length=1000

type is one of 'vfwavi' (doesn't work), 'ffmpeg', 'jmd', 'nut', 'wave'
name is filename to dump to; might be auto-modified to add segment split names (_00, _01, etc)
length is length of dump in frames after which it auto-stops.  if omitted, set to be equal to the length of the movie loaded with --movie, or if not that, it runs forever (can be stopped from UI)
This commit is contained in:
goyuken 2012-07-23 00:33:30 +00:00
parent f9c764f5e5
commit 7db089fbbd
9 changed files with 350 additions and 120 deletions

View File

@ -669,6 +669,19 @@ namespace BizHawk.MultiClient
{ {
return "avi"; return "avi";
} }
public void SetDefaultVideoCodecToken()
{
throw new NotImplementedException();
}
public string ShortName()
{
return "vfwavi";
}
} }
} }

View File

@ -232,6 +232,8 @@ namespace BizHawk.MultiClient
public void Dispose() public void Dispose()
{ {
if (ffmpeg != null)
CloseFile();
} }
@ -274,5 +276,16 @@ namespace BizHawk.MultiClient
// this needs to interface with the codec token // this needs to interface with the codec token
return token.defaultext; return token.defaultext;
} }
public void SetDefaultVideoCodecToken()
{
this.token = FFmpegWriterForm.FormatPreset.GetDefaultPreset();
}
public string ShortName()
{
return "ffmpeg";
}
} }
} }

View File

@ -79,6 +79,26 @@ namespace BizHawk.MultiClient
}; };
} }
/// <summary>
/// get the default format preset (from config files)
/// </summary>
/// <returns></returns>
public static FormatPreset GetDefaultPreset()
{
FormatPreset[] fps = GetPresets();
foreach (var fp in fps)
{
if (fp.ToString() == Global.Config.VideoWriter)
{
if (fp.custom)
return fp;
}
}
// default to xvid?
return fps[1];
}
public void Dispose() public void Dispose()
{ {
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using BizHawk.MultiClient;
namespace BizHawk namespace BizHawk
{ {
@ -11,6 +12,11 @@ namespace BizHawk
/// </summary> /// </summary>
void SetVideoCodecToken(IDisposable token); void SetVideoCodecToken(IDisposable token);
/// <summary>
/// sets to a default video codec token without calling any UI - for automated dumping
/// </summary>
void SetDefaultVideoCodecToken();
// why no OpenFile(IEnumerator<string>) ? // why no OpenFile(IEnumerator<string>) ?
// different video writers may have different ideas of how and why splitting is to occur // different video writers may have different ideas of how and why splitting is to occur
@ -83,5 +89,50 @@ namespace BizHawk
/// what default extension this writer would like to put on its output /// what default extension this writer would like to put on its output
/// </summary> /// </summary>
string DesiredExtension(); string DesiredExtension();
/// <summary>
/// name that command line parameters can refer to
/// </summary>
/// <returns></returns>
string ShortName();
}
/// <summary>
/// contains methods to find all IVideoWriter
/// </summary>
public static class VideoWriterInventory
{
public static IEnumerable<IVideoWriter> GetAllVideoWriters()
{
var ret = new IVideoWriter[]
{
new AviWriter(),
new JMDWriter(),
new WavWriterV(),
new FFmpegWriter(),
new NutWriter()
};
return ret;
}
/// <summary>
/// find an IVideoWriter by its short name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static IVideoWriter GetVideoWriter(string name)
{
IVideoWriter ret = null;
var vws = GetAllVideoWriters();
foreach (var vw in vws)
if (vw.ShortName() == name)
ret = vw;
foreach (var vw in vws)
if (vw != ret)
vw.Dispose();
return ret;
}
} }
} }

View File

@ -780,5 +780,26 @@ namespace BizHawk.MultiClient
{ {
return "jmd"; return "jmd";
} }
public void SetDefaultVideoCodecToken()
{
CodecToken ct = new CodecToken();
// load from config and sanitize
int t = Math.Min(Math.Max(Global.Config.JMDThreads, 1), 6);
int c = Math.Min(Math.Max(Global.Config.JMDCompression, Deflater.NO_COMPRESSION), Deflater.BEST_COMPRESSION);
ct.compressionlevel = c;
ct.numthreads = t;
token = ct;
}
public string ShortName()
{
return "jmd";
}
} }
} }

View File

@ -21,7 +21,6 @@ namespace BizHawk.MultiClient
} }
} }
public void SetVideoCodecToken(IDisposable token) public void SetVideoCodecToken(IDisposable token)
{ {
// ignored // ignored
@ -122,9 +121,11 @@ namespace BizHawk.MultiClient
public void Dispose() public void Dispose()
{ {
if (current != null)
endsegment();
baseName = null;
} }
public override string ToString() public override string ToString()
{ {
return ".nut writer"; return ".nut writer";
@ -139,5 +140,16 @@ namespace BizHawk.MultiClient
{ {
return "nut"; return "nut";
} }
public void SetDefaultVideoCodecToken()
{
// ignored
}
public string ShortName()
{
return "nut";
}
} }
} }

View File

@ -25,14 +25,17 @@ namespace BizHawk.MultiClient
/// <param name="list">list of IVideoWriters to choose from</param> /// <param name="list">list of IVideoWriters to choose from</param>
/// <param name="owner">parent window</param> /// <param name="owner">parent window</param>
/// <returns>user choice, or null on Cancel\Close\invalid</returns> /// <returns>user choice, or null on Cancel\Close\invalid</returns>
public static IVideoWriter DoVideoWriterChoserDlg(IVideoWriter[] list, IWin32Window owner) public static IVideoWriter DoVideoWriterChoserDlg(IEnumerable<IVideoWriter> list, IWin32Window owner)
{ {
VideoWriterChooserForm dlg = new VideoWriterChooserForm(); VideoWriterChooserForm dlg = new VideoWriterChooserForm();
dlg.label1.Text = "Description:"; dlg.label1.Text = "Description:";
dlg.label2.Text = ""; dlg.label2.Text = "";
dlg.listBox1.Items.AddRange(list); dlg.listBox1.BeginUpdate();
foreach (var vw in list)
dlg.listBox1.Items.Add(vw);
dlg.listBox1.EndUpdate();
int i = dlg.listBox1.FindStringExact(Global.Config.VideoWriter); int i = dlg.listBox1.FindStringExact(Global.Config.VideoWriter);
if (i != ListBox.NoMatches) if (i != ListBox.NoMatches)
@ -61,6 +64,5 @@ namespace BizHawk.MultiClient
else else
label2.Text = ""; label2.Text = "";
} }
} }
} }

View File

@ -283,5 +283,16 @@ namespace BizHawk.MultiClient
{ {
return "wav"; return "wav";
} }
public void SetDefaultVideoCodecToken()
{
// don't use codec tokens, so don't care
}
public string ShortName()
{
return "wave";
}
} }
} }

View File

@ -82,6 +82,12 @@ namespace BizHawk.MultiClient
public LuaConsole LuaConsole1 = new LuaConsole(); public LuaConsole LuaConsole1 = new LuaConsole();
#endif #endif
/// <summary>
/// number of frames to autodump
/// </summary>
int autoDumpLength = 0;
public MainForm(string[] args) public MainForm(string[] args)
{ {
Global.MovieSession = new MovieSession(); Global.MovieSession = new MovieSession();
@ -168,6 +174,9 @@ namespace BizHawk.MultiClient
string cmdRom = null; string cmdRom = null;
string cmdLoadState = null; string cmdLoadState = null;
string cmdMovie = null; string cmdMovie = null;
string cmdDumpType = null;
string cmdDumpName = null;
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
//for some reason sometimes visual studio will pass this to us on the commandline. it makes no sense. //for some reason sometimes visual studio will pass this to us on the commandline. it makes no sense.
@ -184,6 +193,12 @@ namespace BizHawk.MultiClient
cmdLoadState = arg.Substring(arg.IndexOf('=') + 1); cmdLoadState = arg.Substring(arg.IndexOf('=') + 1);
else if (arg.StartsWith("--movie=")) else if (arg.StartsWith("--movie="))
cmdMovie = arg.Substring(arg.IndexOf('=') + 1); cmdMovie = arg.Substring(arg.IndexOf('=') + 1);
else if (arg.StartsWith("--dump-type="))
cmdDumpType = arg.Substring(arg.IndexOf('=') + 1);
else if (arg.StartsWith("--dump-name="))
cmdDumpName = arg.Substring(arg.IndexOf('=') + 1);
else if (arg.StartsWith("--dump-length="))
int.TryParse(arg.Substring(arg.IndexOf('=') + 1), out autoDumpLength);
else else
cmdRom = arg; cmdRom = arg;
} }
@ -208,6 +223,9 @@ namespace BizHawk.MultiClient
{ {
Movie m = new Movie(cmdMovie, MOVIEMODE.PLAY); Movie m = new Movie(cmdMovie, MOVIEMODE.PLAY);
ReadOnly = true; ReadOnly = true;
// if user is dumping and didnt supply dump length, make it as long as the loaded movie
if (autoDumpLength == 0)
autoDumpLength = m.LogLength();
StartNewMovie(m, false); StartNewMovie(m, false);
Global.Config.RecentMovies.Add(cmdMovie); Global.Config.RecentMovies.Add(cmdMovie);
} }
@ -268,6 +286,12 @@ namespace BizHawk.MultiClient
debuggerToolStripMenuItem.Enabled = false; debuggerToolStripMenuItem.Enabled = false;
//luaConsoleToolStripMenuItem.Enabled = false; //luaConsoleToolStripMenuItem.Enabled = false;
} }
// start dumping, if appropriate
if (cmdDumpType != null && cmdDumpName != null)
{
RecordAVI(cmdDumpType, cmdDumpName);
}
} }
/// <summary> /// <summary>
@ -1966,6 +1990,13 @@ namespace BizHawk.MultiClient
CurrAviWriter.AddFrame(Global.Emulator.VideoProvider); CurrAviWriter.AddFrame(Global.Emulator.VideoProvider);
CurrAviWriter.AddSamples(temp); CurrAviWriter.AddSamples(temp);
if (autoDumpLength > 0)
{
autoDumpLength--;
if (autoDumpLength == 0) // finish
StopAVI();
}
} }
@ -2762,21 +2793,65 @@ namespace BizHawk.MultiClient
if (Global.Config.SaveSlot == 9) StatusSlot9.BackColor = SystemColors.ControlLightLight; if (Global.Config.SaveSlot == 9) StatusSlot9.BackColor = SystemColors.ControlLightLight;
} }
/// <summary>
/// start avi recording, unattended
/// </summary>
/// <param name="videowritername">match the short name of an ivideowriter</param>
/// <param name="filename">filename to save to</param>
public void RecordAVI(string videowritername, string filename)
{
_RecordAVI(videowritername, filename, true);
}
/// <summary>
/// start avi recording, asking user for filename and options
/// </summary>
public void RecordAVI() public void RecordAVI()
{
_RecordAVI(null, null, false);
}
/// <summary>
/// start avi recording
/// </summary>
/// <param name="videowritername"></param>
/// <param name="filename"></param>
/// <param name="unattended"></param>
private void _RecordAVI(string videowritername, string filename, bool unattended)
{ {
if (CurrAviWriter != null) return; if (CurrAviWriter != null) return;
// select IVideoWriter to use // select IVideoWriter to use
IVideoWriter aw = null;
var writers = VideoWriterInventory.GetAllVideoWriters();
if (unattended)
{
foreach (var w in writers)
{
if (w.ShortName() == videowritername)
{
aw = w;
break;
}
}
}
else
{
aw = VideoWriterChooserForm.DoVideoWriterChoserDlg(writers, Global.MainForm);
}
var writers = new IVideoWriter[]{new AviWriter(), new JMDWriter(), new WavWriterV(), new FFmpegWriter(), new NutWriter()};
IVideoWriter aw = VideoWriterChooserForm.DoVideoWriterChoserDlg(writers, Global.MainForm);
foreach (var w in writers) foreach (var w in writers)
{ {
if (w != aw) if (w != aw)
w.Dispose(); w.Dispose();
} }
if (aw == null) if (aw == null)
{ {
if (unattended)
Global.OSD.AddMessage(string.Format("Couldn't start video writer \"{0}\"", videowritername));
else
Global.OSD.AddMessage("A/V capture canceled."); Global.OSD.AddMessage("A/V capture canceled.");
return; return;
} }
@ -2789,7 +2864,12 @@ namespace BizHawk.MultiClient
// select codec token // select codec token
// do this before save dialog because ffmpeg won't know what extension it wants until it's been configured // do this before save dialog because ffmpeg won't know what extension it wants until it's been configured
if (unattended)
{
aw.SetDefaultVideoCodecToken();
}
else
{
var token = aw.AcquireVideoCodecToken(Global.MainForm); var token = aw.AcquireVideoCodecToken(Global.MainForm);
if (token == null) if (token == null)
{ {
@ -2798,9 +2878,15 @@ namespace BizHawk.MultiClient
return; return;
} }
aw.SetVideoCodecToken(token); aw.SetVideoCodecToken(token);
}
// select file to save to // select file to save to
if (unattended)
{
aw.OpenFile(filename);
}
else
{
var sfd = new SaveFileDialog(); var sfd = new SaveFileDialog();
if (!(Global.Emulator is NullEmulator)) if (!(Global.Emulator is NullEmulator))
{ {
@ -2823,8 +2909,8 @@ namespace BizHawk.MultiClient
aw.Dispose(); aw.Dispose();
return; return;
} }
aw.OpenFile(sfd.FileName); aw.OpenFile(sfd.FileName);
}
//commit the avi writing last, in case there were any errors earlier //commit the avi writing last, in case there were any errors earlier
CurrAviWriter = aw; CurrAviWriter = aw;
@ -2852,6 +2938,7 @@ namespace BizHawk.MultiClient
return; return;
} }
CurrAviWriter.CloseFile(); CurrAviWriter.CloseFile();
CurrAviWriter.Dispose();
CurrAviWriter = null; CurrAviWriter = null;
Global.OSD.AddMessage("AVI capture stopped"); Global.OSD.AddMessage("AVI capture stopped");
AVIStatusLabel.Image = BizHawk.MultiClient.Properties.Resources.Blank; AVIStatusLabel.Image = BizHawk.MultiClient.Properties.Resources.Blank;