diff --git a/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs b/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs
index 1029725802..b937f06244 100644
--- a/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs
@@ -10,6 +10,8 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
+ [VideoWriter("vfwavi", "AVI writer",
+ "Uses the Microsoft AVIFIL32 system to write .avi files. Audio is uncompressed; Video can be compressed with any installed VCM codec. Splits on 2G and resolution change.")]
class AviWriter : IVideoWriter
{
CodecToken currVideoCodecToken = null;
@@ -850,22 +852,6 @@ namespace BizHawk.Client.EmuHawk
}
}
-
- public override string ToString()
- {
- return "AVI writer";
- }
-
- public string WriterDescription()
- {
- return "Uses the Microsoft AVIFIL32 system to write .avi files. Audio is uncompressed; Video can be compressed with any installed VCM codec. Splits on 2G and resolution change.";
- }
-
- public string DesiredExtension()
- {
- return "avi";
- }
-
public void SetDefaultVideoCodecToken()
{
CodecToken ct = CodecToken.DeSerialize(Global.Config.AVICodecToken);
@@ -874,9 +860,9 @@ namespace BizHawk.Client.EmuHawk
currVideoCodecToken = ct;
}
- public string ShortName()
+ public string DesiredExtension()
{
- return "vfwavi";
+ return "avi";
}
}
}
diff --git a/BizHawk.Client.EmuHawk/AVOut/FFmpegWriter.cs b/BizHawk.Client.EmuHawk/AVOut/FFmpegWriter.cs
index c205d6ca87..c5c53f92e3 100644
--- a/BizHawk.Client.EmuHawk/AVOut/FFmpegWriter.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/FFmpegWriter.cs
@@ -11,6 +11,7 @@ namespace BizHawk.Client.EmuHawk
///
/// uses pipes to launch an external ffmpeg process and encode
///
+ [VideoWriter("ffmpeg", "FFmpeg writer", "Uses an external FFMPEG process to encode video and audio. Various formats supported. Splits on resolution change.")]
class FFmpegWriter : IVideoWriter
{
///
@@ -275,31 +276,15 @@ namespace BizHawk.Client.EmuHawk
this.channels = channels;
}
- public override string ToString()
- {
- return "FFmpeg writer";
- }
-
- public string WriterDescription()
- {
- return "Uses an external FFMPEG process to encode video and audio. Various formats supported. Splits on resolution change.";
- }
-
public string DesiredExtension()
{
// this needs to interface with the codec token
return token.defaultext;
}
-
public void SetDefaultVideoCodecToken()
{
token = FFmpegWriterForm.FormatPreset.GetDefaultPreset();
}
-
- public string ShortName()
- {
- return "ffmpeg";
- }
}
}
diff --git a/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs b/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs
index 969267f1d4..45c54f06d4 100644
--- a/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs
@@ -91,7 +91,7 @@ namespace BizHawk.Client.EmuHawk
foreach (var fp in fps)
{
- if (fp.ToString() == Global.Config.VideoWriter)
+ if (fp.ToString() == Global.Config.FFmpegFormat)
{
if (fp.custom)
return fp;
diff --git a/BizHawk.Client.EmuHawk/AVOut/GifWriter.cs b/BizHawk.Client.EmuHawk/AVOut/GifWriter.cs
index 9c019459bb..b82065c3c6 100644
--- a/BizHawk.Client.EmuHawk/AVOut/GifWriter.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/GifWriter.cs
@@ -10,6 +10,7 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
+ [VideoWriter("gif", "GIF writer", "Creates an animated .gif")]
public class GifWriter : IVideoWriter
{
public class GifToken : IDisposable
@@ -212,21 +213,12 @@ namespace BizHawk.Client.EmuHawk
// gif can't support this
}
- public string WriterDescription()
- {
- return "Creates an animated .gif";
- }
public string DesiredExtension()
{
return "gif";
}
- public string ShortName()
- {
- return "gif";
- }
-
public void Dispose()
{
if (f != null)
@@ -235,10 +227,5 @@ namespace BizHawk.Client.EmuHawk
f = null;
}
}
-
- public override string ToString()
- {
- return "GIF writer";
- }
}
}
diff --git a/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs b/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs
index d0a1dde644..3b5eaee849 100644
--- a/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs
@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
+using BizHawk.Common.ReflectionExtensions;
namespace BizHawk.Client.EmuHawk
{
@@ -90,7 +91,7 @@ namespace BizHawk.Client.EmuHawk
///
/// short description of this IVideoWriter
///
- string WriterDescription();
+ // string WriterDescription();
///
/// what default extension this writer would like to put on its output
///
@@ -99,7 +100,68 @@ namespace BizHawk.Client.EmuHawk
/// name that command line parameters can refer to
///
///
- string ShortName();
+ // string ShortName();
+ }
+
+ public static class VideoWriterExtensions
+ {
+ public static string WriterDescription(this IVideoWriter w)
+ {
+ return w.GetAttribute().Description;
+ }
+
+ public static string ShortName(this IVideoWriter w)
+ {
+ return w.GetAttribute().ShortName;
+ }
+
+ public static string LongName(this IVideoWriter w)
+ {
+ return w.GetAttribute().Name;
+ }
+ }
+
+
+ [AttributeUsage(AttributeTargets.Class)]
+ public class VideoWriterAttribute : Attribute
+ {
+ public string ShortName { get; private set; }
+ public string Name { get; private set; }
+ public string Description { get; private set; }
+
+ public VideoWriterAttribute(string ShortName, string Name, string Description)
+ {
+ this.ShortName = ShortName;
+ this.Name = Name;
+ this.Description = Description;
+ }
+ }
+
+ [AttributeUsage(AttributeTargets.Class)]
+ public class VideoWriterIgnoreAttribute : Attribute
+ {
+ }
+
+ public class VideoWriterInfo
+ {
+ public VideoWriterAttribute Attribs { get; private set; }
+ private Type type;
+
+ public VideoWriterInfo(VideoWriterAttribute Attribs, Type type)
+ {
+ this.type = type;
+ this.Attribs = Attribs;
+ }
+
+ public IVideoWriter Create()
+ {
+ return (IVideoWriter)Activator.CreateInstance(type);
+ }
+
+ public override string ToString()
+ {
+ return Attribs.Name;
+ }
}
///
@@ -107,19 +169,26 @@ namespace BizHawk.Client.EmuHawk
///
public static class VideoWriterInventory
{
- public static IEnumerable GetAllVideoWriters()
+ private static Dictionary vws = new Dictionary();
+
+ static VideoWriterInventory()
{
- var ret = new IVideoWriter[]
- {
- new AviWriter(),
- new JMDWriter(),
- new WavWriterV(),
- new FFmpegWriter(),
- new NutWriter(),
- new GifWriter(),
- new SynclessRecorder()
- };
- return ret;
+ foreach (Type t in typeof(VideoWriterInventory).Assembly.GetTypes())
+ {
+ if (!t.IsInterface
+ && typeof(IVideoWriter).IsAssignableFrom(t)
+ && !t.IsAbstract
+ && t.GetCustomAttributes(typeof(VideoWriterIgnoreAttribute), false).Length == 0)
+ {
+ var a = (VideoWriterAttribute)t.GetCustomAttributes(typeof(VideoWriterAttribute), false)[0];
+ vws.Add(a.ShortName, new VideoWriterInfo(a, t));
+ }
+ }
+ }
+
+ public static IEnumerable GetAllWriters()
+ {
+ return vws.Values;
}
///
@@ -129,18 +198,11 @@ namespace BizHawk.Client.EmuHawk
///
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;
+ VideoWriterInfo ret;
+ if (vws.TryGetValue(name, out ret))
+ return ret.Create();
+ else
+ return null;
}
}
}
diff --git a/BizHawk.Client.EmuHawk/AVOut/JMDWriter.cs b/BizHawk.Client.EmuHawk/AVOut/JMDWriter.cs
index 5ba9d0b80b..2121e9787e 100644
--- a/BizHawk.Client.EmuHawk/AVOut/JMDWriter.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/JMDWriter.cs
@@ -18,6 +18,7 @@ namespace BizHawk.Client.EmuHawk
/// so each dump is always one file
/// they can be processed with JPC-rr streamtools or JMDSource (avisynth)
///
+ [VideoWriter("jmd", "JMD writer", "Writes a JPC-rr multidump file (JMD). These can be read and further processed with jpc-streamtools. One JMD file contains all audio (uncompressed) and video (compressed).")]
class JMDWriter : IVideoWriter
{
///
@@ -768,23 +769,11 @@ namespace BizHawk.Client.EmuHawk
moviemetadata.rerecords = rerecords;
}
-
- public override string ToString()
- {
- return "JMD writer";
- }
-
- public string WriterDescription()
- {
- return "Writes a JPC-rr multidump file (JMD). These can be read and further processed with jpc-streamtools. One JMD file contains all audio (uncompressed) and video (compressed).";
- }
-
public string DesiredExtension()
{
return "jmd";
}
-
public void SetDefaultVideoCodecToken()
{
CodecToken ct = new CodecToken();
@@ -800,11 +789,6 @@ namespace BizHawk.Client.EmuHawk
token = ct;
}
- public string ShortName()
- {
- return "jmd";
- }
-
public void SetFrame(int frame) { }
}
}
diff --git a/BizHawk.Client.EmuHawk/AVOut/NutWriter.cs b/BizHawk.Client.EmuHawk/AVOut/NutWriter.cs
index f1c2ceb969..011b5d8ee0 100644
--- a/BizHawk.Client.EmuHawk/AVOut/NutWriter.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/NutWriter.cs
@@ -11,6 +11,7 @@ namespace BizHawk.Client.EmuHawk
/// dumps in the "nut" container format
/// uncompressed video and audio
///
+ [VideoWriter("nut", "NUT writer", "Writes a series of .nut files to disk, a container format which can be opened by ffmpeg. All data is uncompressed. Splits occur on resolution changes. NOT RECCOMENDED FOR USE.")]
class NutWriter : IVideoWriter
{
///
@@ -128,30 +129,14 @@ namespace BizHawk.Client.EmuHawk
baseName = null;
}
- public override string ToString()
- {
- return "NUT writer";
- }
-
- public string WriterDescription()
- {
- return "Writes a series of .nut files to disk, a container format which can be opened by ffmpeg. All data is uncompressed. Splits occur on resolution changes. NOT RECCOMENDED FOR USE.";
- }
-
public string DesiredExtension()
{
return "nut";
}
-
public void SetDefaultVideoCodecToken()
{
// ignored
}
-
- public string ShortName()
- {
- return "nut";
- }
}
}
diff --git a/BizHawk.Client.EmuHawk/AVOut/SynclessRecorder.cs b/BizHawk.Client.EmuHawk/AVOut/SynclessRecorder.cs
index 3aea2a9dcf..31a05ba85b 100644
--- a/BizHawk.Client.EmuHawk/AVOut/SynclessRecorder.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/SynclessRecorder.cs
@@ -14,6 +14,7 @@ using BizHawk.Bizware.BizwareGL;
namespace BizHawk.Client.EmuHawk
{
+ [VideoWriter("syncless", "Syncless Recording", "Writes each frame to a directory as a PNG and WAV pair, identified by frame number. The results can be exported into one video file.")]
public class SynclessRecorder : IVideoWriter
{
public void Dispose() { }
@@ -95,19 +96,8 @@ namespace BizHawk.Client.EmuHawk
//not needed
}
- public override string ToString()
- {
- return "Syncless Recording";
- }
-
- public string WriterDescription()
- {
- return "Writes each frame to a directory as a PNG and WAV pair, identified by frame number. The results can be exported into one video file.";
- }
-
public string DesiredExtension() { return "syncless.txt"; }
- public string ShortName() { return "syncless"; }
///
/// splits the string into chunks of length s
@@ -148,4 +138,4 @@ namespace BizHawk.Client.EmuHawk
}
-}
\ No newline at end of file
+}
diff --git a/BizHawk.Client.EmuHawk/AVOut/VideoWriterChooserForm.cs b/BizHawk.Client.EmuHawk/AVOut/VideoWriterChooserForm.cs
index 5f06024cb2..2bb89227ad 100644
--- a/BizHawk.Client.EmuHawk/AVOut/VideoWriterChooserForm.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/VideoWriterChooserForm.cs
@@ -27,20 +27,26 @@ namespace BizHawk.Client.EmuHawk
/// list of IVideoWriters to choose from
/// parent window
/// user choice, or null on Cancel\Close\invalid
- public static IVideoWriter DoVideoWriterChoserDlg(IEnumerable list, IWin32Window owner, out int resizew, out int resizeh, out bool pad)
+ public static IVideoWriter DoVideoWriterChoserDlg(IEnumerable list, IWin32Window owner, out int resizew, out int resizeh, out bool pad)
{
VideoWriterChooserForm dlg = new VideoWriterChooserForm();
dlg.labelDescriptionBody.Text = "";
- dlg.listBox1.BeginUpdate();
- foreach (var vw in list)
- dlg.listBox1.Items.Add(vw);
- dlg.listBox1.EndUpdate();
-
- int i = dlg.listBox1.FindStringExact(Global.Config.VideoWriter);
- if (i != ListBox.NoMatches)
- dlg.listBox1.SelectedIndex = i;
+ {
+ int idx = 0;
+ int idx_select = -1;
+ dlg.listBox1.BeginUpdate();
+ foreach (var vw in list)
+ {
+ dlg.listBox1.Items.Add(vw);
+ if (vw.Attribs.ShortName == Global.Config.VideoWriter)
+ idx_select = idx;
+ idx++;
+ }
+ dlg.listBox1.SelectedIndex = idx_select;
+ dlg.listBox1.EndUpdate();
+ }
foreach (Control c in dlg.panelSizeSelect.Controls)
c.Enabled = false;
@@ -51,11 +57,14 @@ namespace BizHawk.Client.EmuHawk
if (result == DialogResult.OK && dlg.listBox1.SelectedIndex != -1)
{
- ret = (IVideoWriter)dlg.listBox1.SelectedItem;
- Global.Config.VideoWriter = ret.ToString();
+ var vwi = (VideoWriterInfo)dlg.listBox1.SelectedItem;
+ ret = vwi.Create();
+ Global.Config.VideoWriter = vwi.Attribs.ShortName;
}
else
+ {
ret = null;
+ }
if (ret != null && dlg.checkBoxResize.Checked)
{
@@ -77,7 +86,7 @@ namespace BizHawk.Client.EmuHawk
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex != -1)
- labelDescriptionBody.Text = ((IVideoWriter)listBox1.SelectedItem).WriterDescription();
+ labelDescriptionBody.Text = ((VideoWriterInfo)listBox1.SelectedItem).Attribs.Description;
else
labelDescriptionBody.Text = "";
}
diff --git a/BizHawk.Client.EmuHawk/AVOut/WavWriter.cs b/BizHawk.Client.EmuHawk/AVOut/WavWriter.cs
index a2cd607e60..6d0ff888bb 100644
--- a/BizHawk.Client.EmuHawk/AVOut/WavWriter.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/WavWriter.cs
@@ -196,6 +196,7 @@ namespace BizHawk.Client.EmuHawk
///
/// slim wrapper on WavWriter that implements IVideoWriter (discards all video!)
///
+ [VideoWriter("wave", "WAV writer", "Writes a series of standard RIFF wav files containing uncompressed audio. Does not write video. Splits every 2G.")]
public class WavWriterV : IVideoWriter
{
public void SetVideoCodecToken(IDisposable token) { }
@@ -273,30 +274,14 @@ namespace BizHawk.Client.EmuHawk
wavwriter.writesamples(samples);
}
- public override string ToString()
- {
- return "WAV writer";
- }
-
- public string WriterDescription()
- {
- return "Writes a series of standard RIFF wav files containing uncompressed audio. Does not write video. Splits every 2G.";
- }
-
public string DesiredExtension()
{
return "wav";
}
-
public void SetDefaultVideoCodecToken()
{
// don't use codec tokens, so don't care
}
-
- public string ShortName()
- {
- return "wave";
- }
}
}
diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs
index bd250192b7..6ae59bf7bc 100644
--- a/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.cs
@@ -2782,28 +2782,15 @@ namespace BizHawk.Client.EmuHawk
// select IVideoWriter to use
IVideoWriter aw = null;
- var writers = VideoWriterInventory.GetAllVideoWriters();
- var video_writers = writers as IVideoWriter[] ?? writers.ToArray();
if (unattended)
{
- foreach (var w in video_writers.Where(w => w.ShortName() == videowritername))
- {
- aw = w;
- break;
- }
+ aw = VideoWriterInventory.GetVideoWriter(videowritername);
+
}
else
{
- aw = VideoWriterChooserForm.DoVideoWriterChoserDlg(video_writers, GlobalWin.MainForm, out _avwriterResizew, out _avwriterResizeh, out _avwriterpad);
- }
-
- foreach (var w in video_writers)
- {
- if (w != aw)
- {
- w.Dispose();
- }
+ aw = VideoWriterChooserForm.DoVideoWriterChoserDlg(VideoWriterInventory.GetAllWriters(), GlobalWin.MainForm, out _avwriterResizew, out _avwriterResizeh, out _avwriterpad);
}
if (aw == null)
diff --git a/BizHawk.Common/Extensions/ReflectionExtensions.cs b/BizHawk.Common/Extensions/ReflectionExtensions.cs
index 6b7c1878c3..67fc2500ad 100644
--- a/BizHawk.Common/Extensions/ReflectionExtensions.cs
+++ b/BizHawk.Common/Extensions/ReflectionExtensions.cs
@@ -155,5 +155,10 @@ namespace BizHawk.Common.ReflectionExtensions
yield return v.GetDescription();
}
}
+
+ public static T GetAttribute(this object o)
+ {
+ return (T)o.GetType().GetCustomAttributes(typeof(T), false)[0];
+ }
}
}