using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
public interface IVideoWriter : IDisposable
{
///
/// sets the codec token to be used for video compression
///
void SetVideoCodecToken(IDisposable token);
///
/// sets to a default video codec token without calling any UI - for automated dumping
///
void SetDefaultVideoCodecToken();
///
/// Returns whether this VideoWriter dumps audio
///
bool UsesAudio { get; }
///
/// Returns whether this VideoWriter dumps video
///
bool UsesVideo { get; }
// why no OpenFile(IEnumerator) ?
// different video writers may have different ideas of how and why splitting is to occur
///
/// opens a recording stream
/// set a video codec token first.
///
void OpenFile(string baseName);
///
/// close recording stream
///
void CloseFile();
///
/// tells which emulation frame we're on. Happens before AddFrame() or AddSamples()
///
void SetFrame(int frame);
///
/// adds a frame to the stream
///
void AddFrame(IVideoProvider source);
///
/// adds audio samples to the stream
/// no attempt is made to sync this to the video
/// recommendation: try not to have the size or pacing of the audio chunks be too "weird"
///
void AddSamples(short[] samples);
///
/// obtain a set of recording compression parameters
/// return null on user cancel
///
/// hwnd to attach to if the user is shown config dialog
/// codec token, dispose of it when you're done with it
IDisposable AcquireVideoCodecToken(System.Windows.Forms.IWin32Window hwnd);
///
/// set framerate to fpsNum/fpsDen (assumed to be unchanging over the life of the stream)
///
void SetMovieParameters(int fpsNum, int fpsDen);
///
/// set resolution parameters (width x height)
/// must be set before file is opened
/// can be changed in future
/// should always match IVideoProvider
///
void SetVideoParameters(int width, int height);
///
/// set audio parameters. cannot change later
///
void SetAudioParameters(int sampleRate, int channels, int bits);
///
/// set metadata parameters; should be called before opening file
/// ok to not set at all, if not applicable
///
/// The name of the game loaded
/// Authors on movie file
/// Length of movie file in milliseconds
/// Number of rerecords on movie file
void SetMetaData(string gameName, string authors, ulong lengthMs, ulong rerecords);
///
/// what default extension this writer would like to put on its output
///
string DesiredExtension();
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class VideoWriterAttribute : Attribute
{
public string ShortName { get; }
public string Name { get; }
public string Description { get; }
public VideoWriterAttribute(string shortName, string name, string description)
{
ShortName = shortName;
Name = name;
Description = description;
}
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class VideoWriterIgnoreAttribute : Attribute
{
}
public class VideoWriterInfo
{
public VideoWriterAttribute Attribs { get; }
private readonly Type _type;
public VideoWriterInfo(VideoWriterAttribute attribs, Type type)
{
_type = type;
Attribs = attribs;
}
public IVideoWriter Create() => (IVideoWriter)Activator.CreateInstance(_type);
public override string ToString() => Attribs.Name;
}
///
/// contains methods to find all IVideoWriter
///
public static class VideoWriterInventory
{
private static readonly Dictionary VideoWriters = new Dictionary();
static VideoWriterInventory()
{
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];
VideoWriters.Add(a.ShortName, new VideoWriterInfo(a, t));
}
}
}
public static IEnumerable GetAllWriters() => VideoWriters.Values;
///
/// find an IVideoWriter by its short name
///
public static IVideoWriter GetVideoWriter(string name)
{
return VideoWriters.TryGetValue(name, out var ret)
? ret.Create()
: null;
}
}
}