AVI: Added camstudio codec support + compression level slider

This commit is contained in:
Souryo 2017-01-01 10:15:42 -05:00
parent f468b0502b
commit d805ac2d3c
29 changed files with 391 additions and 52 deletions

View file

@ -23,7 +23,7 @@ AviRecorder::~AviRecorder()
} }
} }
bool AviRecorder::StartRecording(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate) bool AviRecorder::StartRecording(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel)
{ {
if(!_recording) { if(!_recording) {
_outputFile = filename; _outputFile = filename;
@ -32,7 +32,7 @@ bool AviRecorder::StartRecording(string filename, VideoCodec codec, uint32_t wid
_frameBuffer = new uint8_t[_frameBufferLength]; _frameBuffer = new uint8_t[_frameBufferLength];
_aviWriter.reset(new AviWriter()); _aviWriter.reset(new AviWriter());
if(!_aviWriter->StartWrite(filename, codec, width, height, bpp, fps, audioSampleRate)) { if(!_aviWriter->StartWrite(filename, codec, width, height, bpp, fps, audioSampleRate, compressionLevel)) {
_aviWriter.reset(); _aviWriter.reset();
return false; return false;
} }

View file

@ -26,7 +26,7 @@ public:
AviRecorder(); AviRecorder();
virtual ~AviRecorder(); virtual ~AviRecorder();
bool StartRecording(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate); bool StartRecording(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel);
void StopRecording(); void StopRecording();
void AddFrame(void* frameBuffer); void AddFrame(void* frameBuffer);

View file

@ -217,13 +217,13 @@ void VideoDecoder::TakeScreenshot()
} }
} }
void VideoDecoder::StartRecording(string filename, VideoCodec codec) void VideoDecoder::StartRecording(string filename, VideoCodec codec, uint32_t compressionLevel)
{ {
if(_videoFilter) { if(_videoFilter) {
shared_ptr<AviRecorder> recorder(new AviRecorder()); shared_ptr<AviRecorder> recorder(new AviRecorder());
FrameInfo frameInfo = _videoFilter->GetFrameInfo(); FrameInfo frameInfo = _videoFilter->GetFrameInfo();
if(recorder->StartRecording(filename, codec, frameInfo.Width, frameInfo.Height, frameInfo.BitsPerPixel, 60098814, EmulationSettings::GetSampleRate())) { if(recorder->StartRecording(filename, codec, frameInfo.Width, frameInfo.Height, frameInfo.BitsPerPixel, 60098814, EmulationSettings::GetSampleRate(), compressionLevel)) {
_aviRecorder = recorder; _aviRecorder = recorder;
} }
} }

View file

@ -70,7 +70,7 @@ public:
void StartThread(); void StartThread();
void StopThread(); void StopThread();
void StartRecording(string filename, VideoCodec codec); void StartRecording(string filename, VideoCodec codec, uint32_t compressionLevel);
void AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate); void AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate);
void StopRecording(); void StopRecording();
bool IsRecording(); bool IsRecording();

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Config
{
public class AviRecordInfo
{
public VideoCodec Codec = VideoCodec.CSCD;
public UInt32 CompressionLevel = 6;
}
}

View file

@ -28,6 +28,7 @@ namespace Mesen.GUI.Config
public ServerInfo ServerInfo; public ServerInfo ServerInfo;
public PlayerProfile Profile; public PlayerProfile Profile;
public DebugInfo DebugInfo; public DebugInfo DebugInfo;
public AviRecordInfo AviRecordInfo;
public Configuration() public Configuration()
{ {
@ -43,6 +44,7 @@ namespace Mesen.GUI.Config
Cheats = new List<CheatInfo>(); Cheats = new List<CheatInfo>();
VsConfig = new List<VsConfigInfo>(); VsConfig = new List<VsConfigInfo>();
DebugInfo = new DebugInfo(); DebugInfo = new DebugInfo();
AviRecordInfo = new AviRecordInfo();
} }
~Configuration() ~Configuration()

View file

@ -166,5 +166,10 @@
<Value ID="NotEqual">Not equal</Value> <Value ID="NotEqual">Not equal</Value>
<Value ID="Greater">Greater</Value> <Value ID="Greater">Greater</Value>
</Enum> </Enum>
<Enum ID="VideoCodec">
<Value ID="None">None (Uncompressed)</Value>
<Value ID="ZMBV">Zip Motion Block Video (ZMBV)</Value>
<Value ID="CSCD">Camstudio (CSCD)</Value>
</Enum>
</Enums> </Enums>
</Resources> </Resources>

View file

@ -482,7 +482,10 @@
</Form> </Form>
<Form ID="frmRecordAvi" Title="Video Recorder"> <Form ID="frmRecordAvi" Title="Video Recorder">
<Control ID="lblAviFile">Save to:</Control> <Control ID="lblAviFile">Save to:</Control>
<Control ID="chkUseCompression">Use ZMBV compression</Control> <Control ID="lblCodec">Video Codec:</Control>
<Control ID="lblCompressionLevel">Compression Level:</Control>
<Control ID="lblLowCompression">low&#13;(fast)</Control>
<Control ID="lblHighCompression">high&#13;(slow)</Control>
<Control ID="btnBrowse">Browse...</Control> <Control ID="btnBrowse">Browse...</Control>
<Control ID="btnOK">OK</Control> <Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Cancelar</Control> <Control ID="btnCancel">Cancelar</Control>
@ -652,5 +655,10 @@
<Value ID="Spanish">Español</Value> <Value ID="Spanish">Español</Value>
<Value ID="Ukrainian">Українська</Value> <Value ID="Ukrainian">Українська</Value>
</Enum> </Enum>
<Enum ID="VideoCodec">
<Value ID="None">None (Uncompressed)</Value>
<Value ID="ZMBV">Zip Motion Block Video (ZMBV)</Value>
<Value ID="CSCD">Camstudio (CSCD)</Value>
</Enum>
</Enums> </Enums>
</Resources> </Resources>

View file

@ -495,7 +495,10 @@
</Form> </Form>
<Form ID="frmRecordAvi" Title="Enregistreur vidéo"> <Form ID="frmRecordAvi" Title="Enregistreur vidéo">
<Control ID="lblAviFile">Enregistrer sous:</Control> <Control ID="lblAviFile">Enregistrer sous:</Control>
<Control ID="chkUseCompression">Utiliser la compression ZMBV</Control> <Control ID="lblCodec">Codec vidéo :</Control>
<Control ID="lblCompressionLevel">Niveau de compression :</Control>
<Control ID="lblLowCompression">faible&#13;(rapide)</Control>
<Control ID="lblHighCompression">élevé&#13;(lent)</Control>
<Control ID="btnBrowse">Parcourir...</Control> <Control ID="btnBrowse">Parcourir...</Control>
<Control ID="btnOK">OK</Control> <Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Annuler</Control> <Control ID="btnCancel">Annuler</Control>
@ -667,5 +670,10 @@
<Value ID="NotEqual">Pas égale</Value> <Value ID="NotEqual">Pas égale</Value>
<Value ID="Greater">Plus grande</Value> <Value ID="Greater">Plus grande</Value>
</Enum> </Enum>
<Enum ID="VideoCodec">
<Value ID="None">Aucun (Vidéo non-compressé)</Value>
<Value ID="ZMBV">Zip Motion Block Video (ZMBV)</Value>
<Value ID="CSCD">Camstudio (CSCD)</Value>
</Enum>
</Enums> </Enums>
</Resources> </Resources>

View file

@ -477,7 +477,10 @@
</Form> </Form>
<Form ID="frmRecordAvi" Title="動画レコーダー"> <Form ID="frmRecordAvi" Title="動画レコーダー">
<Control ID="lblAviFile">保存先:</Control> <Control ID="lblAviFile">保存先:</Control>
<Control ID="chkUseCompression">ZMBV圧縮を利用する</Control> <Control ID="lblCodec">ビデオコーデック:</Control>
<Control ID="lblCompressionLevel">圧縮レベル:</Control>
<Control ID="lblLowCompression">低い&#13;(早い)</Control>
<Control ID="lblHighCompression">高い&#13;(遅い)</Control>
<Control ID="btnBrowse">参照...</Control> <Control ID="btnBrowse">参照...</Control>
<Control ID="btnOK">OK</Control> <Control ID="btnOK">OK</Control>
<Control ID="btnCancel">キャンセル</Control> <Control ID="btnCancel">キャンセル</Control>
@ -649,5 +652,10 @@
<Value ID="NotEqual">とは違う</Value> <Value ID="NotEqual">とは違う</Value>
<Value ID="Greater">より大きい</Value> <Value ID="Greater">より大きい</Value>
</Enum> </Enum>
<Enum ID="VideoCodec">
<Value ID="None">圧縮なし</Value>
<Value ID="ZMBV">Zip Motion Block Video (ZMBV)</Value>
<Value ID="CSCD">Camstudio (CSCD)</Value>
</Enum>
</Enums> </Enums>
</Resources> </Resources>

View file

@ -482,7 +482,10 @@
</Form> </Form>
<Form ID="frmRecordAvi" Title="Video Recorder"> <Form ID="frmRecordAvi" Title="Video Recorder">
<Control ID="lblAviFile">Save to:</Control> <Control ID="lblAviFile">Save to:</Control>
<Control ID="chkUseCompression">Use ZMBV compression</Control> <Control ID="lblCodec">Video Codec:</Control>
<Control ID="lblCompressionLevel">Compression Level:</Control>
<Control ID="lblLowCompression">low&#13;(fast)</Control>
<Control ID="lblHighCompression">high&#13;(slow)</Control>
<Control ID="btnBrowse">Browse...</Control> <Control ID="btnBrowse">Browse...</Control>
<Control ID="btnOK">OK</Control> <Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Cancelar</Control> <Control ID="btnCancel">Cancelar</Control>
@ -652,5 +655,10 @@
<Value ID="Spanish">Español</Value> <Value ID="Spanish">Español</Value>
<Value ID="Ukrainian">Українська</Value> <Value ID="Ukrainian">Українська</Value>
</Enum> </Enum>
<Enum ID="VideoCodec">
<Value ID="None">None (Uncompressed)</Value>
<Value ID="ZMBV">Zip Motion Block Video (ZMBV)</Value>
<Value ID="CSCD">Camstudio (CSCD)</Value>
</Enum>
</Enums> </Enums>
</Resources> </Resources>

View file

@ -486,7 +486,10 @@
</Form> </Form>
<Form ID="frmRecordAvi" Title="Video Recorder"> <Form ID="frmRecordAvi" Title="Video Recorder">
<Control ID="lblAviFile">Save to:</Control> <Control ID="lblAviFile">Save to:</Control>
<Control ID="chkUseCompression">Use ZMBV compression</Control> <Control ID="lblCodec">Video Codec:</Control>
<Control ID="lblCompressionLevel">Compression Level:</Control>
<Control ID="lblLowCompression">low&#13;(fast)</Control>
<Control ID="lblHighCompression">high&#13;(slow)</Control>
<Control ID="btnBrowse">Browse...</Control> <Control ID="btnBrowse">Browse...</Control>
<Control ID="btnOK">OK</Control> <Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Отмена</Control> <Control ID="btnCancel">Отмена</Control>
@ -658,5 +661,10 @@
<Value ID="NotEqual">Не равно</Value> <Value ID="NotEqual">Не равно</Value>
<Value ID="Greater">Больше</Value> <Value ID="Greater">Больше</Value>
</Enum> </Enum>
<Enum ID="VideoCodec">
<Value ID="None">None (Uncompressed)</Value>
<Value ID="ZMBV">Zip Motion Block Video (ZMBV)</Value>
<Value ID="CSCD">Camstudio (CSCD)</Value>
</Enum>
</Enums> </Enums>
</Resources> </Resources>

View file

@ -485,7 +485,10 @@
</Form> </Form>
<Form ID="frmRecordAvi" Title="Video Recorder"> <Form ID="frmRecordAvi" Title="Video Recorder">
<Control ID="lblAviFile">Save to:</Control> <Control ID="lblAviFile">Save to:</Control>
<Control ID="chkUseCompression">Use ZMBV compression</Control> <Control ID="lblCodec">Video Codec:</Control>
<Control ID="lblCompressionLevel">Compression Level:</Control>
<Control ID="lblLowCompression">low&#13;(fast)</Control>
<Control ID="lblHighCompression">high&#13;(slow)</Control>
<Control ID="btnBrowse">Browse...</Control> <Control ID="btnBrowse">Browse...</Control>
<Control ID="btnOK">OK</Control> <Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Вiдмiна</Control> <Control ID="btnCancel">Вiдмiна</Control>
@ -657,5 +660,10 @@
<Value ID="NotEqual">Не дорівнює</Value> <Value ID="NotEqual">Не дорівнює</Value>
<Value ID="Greater">Бiльше</Value> <Value ID="Greater">Бiльше</Value>
</Enum> </Enum>
<Enum ID="VideoCodec">
<Value ID="None">None (Uncompressed)</Value>
<Value ID="ZMBV">Zip Motion Block Video (ZMBV)</Value>
<Value ID="CSCD">Camstudio (CSCD)</Value>
</Enum>
</Enums> </Enums>
</Resources> </Resources>

View file

@ -956,7 +956,7 @@ namespace Mesen.GUI.Forms
{ {
using(frmRecordAvi frm = new frmRecordAvi()) { using(frmRecordAvi frm = new frmRecordAvi()) {
if(frm.ShowDialog(mnuVideoRecorder) == DialogResult.OK) { if(frm.ShowDialog(mnuVideoRecorder) == DialogResult.OK) {
InteropEmu.AviRecord(frm.Filename, frm.UseCompression ? VideoCodec.ZMBV : VideoCodec.None); InteropEmu.AviRecord(frm.Filename, ConfigManager.Config.AviRecordInfo.Codec, ConfigManager.Config.AviRecordInfo.CompressionLevel);
} }
} }
} }

View file

@ -28,17 +28,27 @@
private void InitializeComponent() private void InitializeComponent()
{ {
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.lblCodec = new System.Windows.Forms.Label();
this.lblAviFile = new System.Windows.Forms.Label(); this.lblAviFile = new System.Windows.Forms.Label();
this.txtFilename = new System.Windows.Forms.TextBox(); this.txtFilename = new System.Windows.Forms.TextBox();
this.btnBrowse = new System.Windows.Forms.Button(); this.btnBrowse = new System.Windows.Forms.Button();
this.chkUseCompression = new System.Windows.Forms.CheckBox(); this.cboVideoCodec = new System.Windows.Forms.ComboBox();
this.lblCompressionLevel = new System.Windows.Forms.Label();
this.lblLowCompression = new System.Windows.Forms.Label();
this.panel1 = new System.Windows.Forms.Panel();
this.trkCompressionLevel = new System.Windows.Forms.TrackBar();
this.lblHighCompression = new System.Windows.Forms.Label();
this.tlpCompressionLevel = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel1.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trkCompressionLevel)).BeginInit();
this.tlpCompressionLevel.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// baseConfigPanel // baseConfigPanel
// //
this.baseConfigPanel.Location = new System.Drawing.Point(0, 66); this.baseConfigPanel.Location = new System.Drawing.Point(0, 99);
this.baseConfigPanel.Size = new System.Drawing.Size(375, 29); this.baseConfigPanel.Size = new System.Drawing.Size(397, 29);
// //
// tableLayoutPanel1 // tableLayoutPanel1
// //
@ -46,21 +56,34 @@
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.lblCodec, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.lblAviFile, 0, 0); this.tableLayoutPanel1.Controls.Add(this.lblAviFile, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.txtFilename, 1, 0); this.tableLayoutPanel1.Controls.Add(this.txtFilename, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.btnBrowse, 2, 0); this.tableLayoutPanel1.Controls.Add(this.btnBrowse, 2, 0);
this.tableLayoutPanel1.Controls.Add(this.chkUseCompression, 0, 1); this.tableLayoutPanel1.Controls.Add(this.cboVideoCodec, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.lblCompressionLevel, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.tlpCompressionLevel, 1, 2);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3; this.tableLayoutPanel1.RowCount = 4;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(375, 95); this.tableLayoutPanel1.Size = new System.Drawing.Size(397, 128);
this.tableLayoutPanel1.TabIndex = 0; this.tableLayoutPanel1.TabIndex = 0;
// //
// lblCodec
//
this.lblCodec.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblCodec.AutoSize = true;
this.lblCodec.Location = new System.Drawing.Point(3, 36);
this.lblCodec.Name = "lblCodec";
this.lblCodec.Size = new System.Drawing.Size(71, 13);
this.lblCodec.TabIndex = 5;
this.lblCodec.Text = "Video Codec:";
//
// lblAviFile // lblAviFile
// //
this.lblAviFile.Anchor = System.Windows.Forms.AnchorStyles.Left; this.lblAviFile.Anchor = System.Windows.Forms.AnchorStyles.Left;
@ -74,15 +97,15 @@
// txtFilename // txtFilename
// //
this.txtFilename.Dock = System.Windows.Forms.DockStyle.Fill; this.txtFilename.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtFilename.Location = new System.Drawing.Point(56, 3); this.txtFilename.Location = new System.Drawing.Point(108, 3);
this.txtFilename.Name = "txtFilename"; this.txtFilename.Name = "txtFilename";
this.txtFilename.ReadOnly = true; this.txtFilename.ReadOnly = true;
this.txtFilename.Size = new System.Drawing.Size(235, 20); this.txtFilename.Size = new System.Drawing.Size(205, 20);
this.txtFilename.TabIndex = 1; this.txtFilename.TabIndex = 1;
// //
// btnBrowse // btnBrowse
// //
this.btnBrowse.Location = new System.Drawing.Point(297, 3); this.btnBrowse.Location = new System.Drawing.Point(319, 3);
this.btnBrowse.Name = "btnBrowse"; this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.Size = new System.Drawing.Size(75, 23); this.btnBrowse.Size = new System.Drawing.Size(75, 23);
this.btnBrowse.TabIndex = 2; this.btnBrowse.TabIndex = 2;
@ -90,25 +113,98 @@
this.btnBrowse.UseVisualStyleBackColor = true; this.btnBrowse.UseVisualStyleBackColor = true;
this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
// //
// chkUseCompression // cboVideoCodec
// //
this.chkUseCompression.AutoSize = true; this.cboVideoCodec.Dock = System.Windows.Forms.DockStyle.Fill;
this.chkUseCompression.Checked = true; this.cboVideoCodec.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.chkUseCompression.CheckState = System.Windows.Forms.CheckState.Checked; this.cboVideoCodec.FormattingEnabled = true;
this.tableLayoutPanel1.SetColumnSpan(this.chkUseCompression, 3); this.cboVideoCodec.Location = new System.Drawing.Point(108, 32);
this.chkUseCompression.Location = new System.Drawing.Point(3, 32); this.cboVideoCodec.Name = "cboVideoCodec";
this.chkUseCompression.Name = "chkUseCompression"; this.cboVideoCodec.Size = new System.Drawing.Size(205, 21);
this.chkUseCompression.Size = new System.Drawing.Size(140, 17); this.cboVideoCodec.TabIndex = 4;
this.chkUseCompression.TabIndex = 3; this.cboVideoCodec.SelectedIndexChanged += new System.EventHandler(this.cboVideoCodec_SelectedIndexChanged);
this.chkUseCompression.Text = "Use ZMBV compression"; //
this.chkUseCompression.UseVisualStyleBackColor = true; // lblCompressionLevel
//
this.lblCompressionLevel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblCompressionLevel.AutoSize = true;
this.lblCompressionLevel.Location = new System.Drawing.Point(3, 67);
this.lblCompressionLevel.Name = "lblCompressionLevel";
this.lblCompressionLevel.Size = new System.Drawing.Size(99, 13);
this.lblCompressionLevel.TabIndex = 6;
this.lblCompressionLevel.Text = "Compression Level:";
//
// lblLowCompression
//
this.lblLowCompression.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblLowCompression.AutoSize = true;
this.lblLowCompression.Location = new System.Drawing.Point(3, 4);
this.lblLowCompression.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
this.lblLowCompression.Name = "lblLowCompression";
this.lblLowCompression.Size = new System.Drawing.Size(30, 26);
this.lblLowCompression.TabIndex = 9;
this.lblLowCompression.Text = "low\r\n(fast)";
this.lblLowCompression.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// panel1
//
this.panel1.Controls.Add(this.trkCompressionLevel);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(36, 3);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(138, 29);
this.panel1.TabIndex = 9;
//
// trkCompressionLevel
//
this.trkCompressionLevel.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkCompressionLevel.Location = new System.Drawing.Point(0, 0);
this.trkCompressionLevel.Maximum = 9;
this.trkCompressionLevel.Minimum = 1;
this.trkCompressionLevel.Name = "trkCompressionLevel";
this.trkCompressionLevel.Size = new System.Drawing.Size(138, 29);
this.trkCompressionLevel.TabIndex = 7;
this.trkCompressionLevel.Value = 1;
//
// lblHighCompression
//
this.lblHighCompression.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblHighCompression.AutoSize = true;
this.lblHighCompression.Location = new System.Drawing.Point(177, 4);
this.lblHighCompression.Margin = new System.Windows.Forms.Padding(0);
this.lblHighCompression.Name = "lblHighCompression";
this.lblHighCompression.Size = new System.Drawing.Size(34, 26);
this.lblHighCompression.TabIndex = 10;
this.lblHighCompression.Text = "high\r\n(slow)";
this.lblHighCompression.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// tlpCompressionLevel
//
this.tlpCompressionLevel.ColumnCount = 3;
this.tlpCompressionLevel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tlpCompressionLevel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpCompressionLevel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tlpCompressionLevel.Controls.Add(this.lblHighCompression, 2, 0);
this.tlpCompressionLevel.Controls.Add(this.panel1, 1, 0);
this.tlpCompressionLevel.Controls.Add(this.lblLowCompression, 0, 0);
this.tlpCompressionLevel.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpCompressionLevel.Location = new System.Drawing.Point(105, 56);
this.tlpCompressionLevel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
this.tlpCompressionLevel.Name = "tlpCompressionLevel";
this.tlpCompressionLevel.RowCount = 1;
this.tlpCompressionLevel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpCompressionLevel.Size = new System.Drawing.Size(211, 35);
this.tlpCompressionLevel.TabIndex = 9;
// //
// frmRecordAvi // frmRecordAvi
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(375, 95); this.ClientSize = new System.Drawing.Size(397, 128);
this.Controls.Add(this.tableLayoutPanel1); this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "frmRecordAvi"; this.Name = "frmRecordAvi";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Video Recording Options"; this.Text = "Video Recording Options";
@ -116,6 +212,11 @@
this.Controls.SetChildIndex(this.baseConfigPanel, 0); this.Controls.SetChildIndex(this.baseConfigPanel, 0);
this.tableLayoutPanel1.ResumeLayout(false); this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout(); this.tableLayoutPanel1.PerformLayout();
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trkCompressionLevel)).EndInit();
this.tlpCompressionLevel.ResumeLayout(false);
this.tlpCompressionLevel.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
} }
@ -126,6 +227,13 @@
private System.Windows.Forms.Label lblAviFile; private System.Windows.Forms.Label lblAviFile;
private System.Windows.Forms.TextBox txtFilename; private System.Windows.Forms.TextBox txtFilename;
private System.Windows.Forms.Button btnBrowse; private System.Windows.Forms.Button btnBrowse;
private System.Windows.Forms.CheckBox chkUseCompression; private System.Windows.Forms.ComboBox cboVideoCodec;
private System.Windows.Forms.Label lblCodec;
private System.Windows.Forms.Label lblCompressionLevel;
private System.Windows.Forms.Label lblLowCompression;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.TrackBar trkCompressionLevel;
private System.Windows.Forms.Label lblHighCompression;
private System.Windows.Forms.TableLayoutPanel tlpCompressionLevel;
} }
} }

View file

@ -16,10 +16,13 @@ namespace Mesen.GUI.Forms
public frmRecordAvi() public frmRecordAvi()
{ {
InitializeComponent(); InitializeComponent();
Entity = ConfigManager.Config.AviRecordInfo;
AddBinding("Codec", cboVideoCodec);
AddBinding("CompressionLevel", trkCompressionLevel);
} }
public string Filename { get; internal set; } public string Filename { get; internal set; }
public bool UseCompression { get; internal set; }
protected override bool ValidateInput() protected override bool ValidateInput()
{ {
@ -31,7 +34,6 @@ namespace Mesen.GUI.Forms
base.OnFormClosed(e); base.OnFormClosed(e);
this.Filename = txtFilename.Text; this.Filename = txtFilename.Text;
this.UseCompression = chkUseCompression.Checked;
} }
private void btnBrowse_Click(object sender, EventArgs e) private void btnBrowse_Click(object sender, EventArgs e)
@ -44,5 +46,11 @@ namespace Mesen.GUI.Forms
txtFilename.Text = sfd.FileName; txtFilename.Text = sfd.FileName;
} }
} }
private void cboVideoCodec_SelectedIndexChanged(object sender, EventArgs e)
{
lblCompressionLevel.Visible = cboVideoCodec.SelectedIndex > 0;
tlpCompressionLevel.Visible = cboVideoCodec.SelectedIndex > 0;
}
} }
} }

View file

@ -205,6 +205,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Config\AviRecordInfo.cs" />
<Compile Include="Config\DebugInfo.cs" /> <Compile Include="Config\DebugInfo.cs" />
<Compile Include="Config\EmulationInfo.cs" /> <Compile Include="Config\EmulationInfo.cs" />
<Compile Include="Config\KeyPresets.cs" /> <Compile Include="Config\KeyPresets.cs" />

View file

@ -91,7 +91,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool MoviePlaying(); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool MoviePlaying();
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool MovieRecording(); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool MovieRecording();
[DllImport(DLLPath)] public static extern void AviRecord([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename, VideoCodec codec); [DllImport(DLLPath)] public static extern void AviRecord([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename, VideoCodec codec, UInt32 compressionLevel);
[DllImport(DLLPath)] public static extern void AviStop(); [DllImport(DLLPath)] public static extern void AviStop();
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool AviIsRecording(); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool AviIsRecording();
@ -1092,6 +1092,7 @@ namespace Mesen.GUI
{ {
None = 0, None = 0,
ZMBV = 1, ZMBV = 1,
CSCD = 2,
} }
public enum VideoFilterType public enum VideoFilterType

View file

@ -300,7 +300,7 @@ namespace InteropEmu {
DllExport bool __stdcall MoviePlaying() { return Movie::Playing(); } DllExport bool __stdcall MoviePlaying() { return Movie::Playing(); }
DllExport bool __stdcall MovieRecording() { return Movie::Recording(); } DllExport bool __stdcall MovieRecording() { return Movie::Recording(); }
DllExport void __stdcall AviRecord(char* filename, VideoCodec codec) { VideoDecoder::GetInstance()->StartRecording(filename, codec); } DllExport void __stdcall AviRecord(char* filename, VideoCodec codec, uint32_t compressionLevel) { VideoDecoder::GetInstance()->StartRecording(filename, codec, compressionLevel); }
DllExport void __stdcall AviStop() { VideoDecoder::GetInstance()->StopRecording(); } DllExport void __stdcall AviStop() { VideoDecoder::GetInstance()->StopRecording(); }
DllExport bool __stdcall AviIsRecording() { return VideoDecoder::GetInstance()->IsRecording(); } DllExport bool __stdcall AviIsRecording() { return VideoDecoder::GetInstance()->IsRecording(); }

View file

@ -26,6 +26,7 @@
#include "BaseCodec.h" #include "BaseCodec.h"
#include "RawCodec.h" #include "RawCodec.h"
#include "ZmbvCodec.h" #include "ZmbvCodec.h"
#include "CamstudioCodec.h"
void AviWriter::WriteAviChunk(const char *tag, uint32_t size, void *data, uint32_t flags) void AviWriter::WriteAviChunk(const char *tag, uint32_t size, void *data, uint32_t flags)
{ {
@ -63,7 +64,7 @@ void AviWriter::host_writed(uint8_t* buffer, uint32_t value)
buffer[3] = value >> 24; buffer[3] = value >> 24;
} }
bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate) bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel)
{ {
_codecType = codec; _codecType = codec;
_file.open(filename, std::ios::out | std::ios::binary); _file.open(filename, std::ios::out | std::ios::binary);
@ -71,13 +72,14 @@ bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, ui
return false; return false;
} }
if(_codecType == VideoCodec::ZMBV) { switch(_codecType) {
_codec.reset(new ZmbvCodec()); default:
} else { case VideoCodec::None: _codec.reset(new RawCodec()); break;
_codec.reset(new RawCodec()); case VideoCodec::ZMBV: _codec.reset(new ZmbvCodec()); break;
case VideoCodec::CSCD: _codec.reset(new CamstudioCodec()); break;
} }
if(!_codec->SetupCompress(width, height)) { if(!_codec->SetupCompress(width, height, compressionLevel)) {
return false; return false;
} }

View file

@ -10,6 +10,7 @@ enum class VideoCodec
{ {
None = 0, None = 0,
ZMBV = 1, ZMBV = 1,
CSCD = 2,
}; };
class AviWriter class AviWriter
@ -50,6 +51,6 @@ public:
void AddFrame(uint8_t* frameData); void AddFrame(uint8_t* frameData);
void AddSound(int16_t * data, uint32_t sampleCount); void AddSound(int16_t * data, uint32_t sampleCount);
bool StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate); bool StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel);
void EndWrite(); void EndWrite();
}; };

View file

@ -4,7 +4,7 @@
class BaseCodec class BaseCodec
{ {
public: public:
virtual bool SetupCompress(int width, int height) = 0; virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) = 0;
virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) = 0; virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) = 0;
virtual const char* GetFourCC() = 0; virtual const char* GetFourCC() = 0;
}; };

View file

@ -0,0 +1,110 @@
//This is based on the code in lsnes' cscd.cpp file
//A few modifications were done to improve compression speed
#include "stdafx.h"
#include "CamstudioCodec.h"
#include "miniz.h"
CamstudioCodec::~CamstudioCodec()
{
if(_prevFrame) {
delete[] _prevFrame;
_prevFrame = nullptr;
}
if(_currentFrame) {
delete[] _currentFrame;
_currentFrame = nullptr;
}
if(_buffer) {
delete[] _buffer;
_buffer = nullptr;
}
if(_compressBuffer) {
delete[] _compressBuffer;
_compressBuffer = nullptr;
}
deflateEnd(&_compressor);
}
bool CamstudioCodec::SetupCompress(int width, int height, uint32_t compressionLevel)
{
_compressionLevel = compressionLevel;
_orgHeight = height;
_orgWidth = width;
_width = (width + 3) & ~3;
_height = (height + 3) & ~3;
_prevFrame = new uint8_t[_width*_height*3]; //24-bit RGB
_currentFrame = new uint8_t[_width*height*3]; //24-bit RGB
_buffer = new uint8_t[_width*height*3]; //24-bit RGB
_compressBufferLength = compressBound(_width*_height * 3) + 2;
_compressBuffer = new uint8_t[_compressBufferLength];
memset(_prevFrame, 0, _width * _height * 3);
memset(_currentFrame, 0, _width * _height * 3);
memset(_buffer, 0, _width * _height * 3);
memset(_compressBuffer, 0, _compressBufferLength);
deflateInit(&_compressor, compressionLevel);
return true;
}
void CamstudioCodec::LoadRow(uint8_t* inPointer, uint8_t* outPointer)
{
for(int x = 0; x < _orgWidth; x++) {
outPointer[0] = inPointer[0];
outPointer[1] = inPointer[1];
outPointer[2] = inPointer[2];
outPointer += 3;
inPointer += 4;
}
}
int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData)
{
deflateReset(&_compressor);
_compressor.next_out = _compressBuffer + 2;
_compressor.avail_out = _compressBufferLength - 2;
_compressBuffer[0] = (isKeyFrame ? 0x03 : 0x02) | (_compressionLevel << 4);
_compressBuffer[1] = 8; //8-bit per color
uint8_t* rowBuffer = _currentFrame;
for(int y = 0; y < _height; y++) {
if(y < _height - _orgHeight) {
memset(rowBuffer, 0, _width * 3);
} else {
LoadRow(frameData + (_height - y - 1) * _orgWidth * 4, rowBuffer);
}
rowBuffer += _width * 3;
}
if(isKeyFrame) {
_compressor.next_in = _currentFrame;
} else {
for(int i = 0, len = _width * _height * 3; i < len; i++) {
_buffer[i] = _currentFrame[i] - _prevFrame[i];
}
_compressor.next_in = _buffer;
}
memcpy(_prevFrame, _currentFrame, _width*_height*3);
_compressor.avail_in = _height * _width * 3;
deflate(&_compressor, MZ_FINISH);
*compressedData = _compressBuffer;
return _compressor.total_out + 2;
}
const char* CamstudioCodec::GetFourCC()
{
return "CSCD";
}

View file

@ -0,0 +1,31 @@
#pragma once
#include "stdafx.h"
#include "BaseCodec.h"
#include "miniz.h"
class CamstudioCodec : public BaseCodec
{
private:
uint8_t* _prevFrame = nullptr;
uint8_t* _currentFrame = nullptr;
uint8_t* _buffer = nullptr;
uint32_t _compressBufferLength = 0;
uint8_t* _compressBuffer = nullptr;
z_stream _compressor = {};
int _compressionLevel = 0;
int _orgWidth = 0;
int _orgHeight = 0;
int _width = 0;
int _height = 0;
void LoadRow(uint8_t* inPointer, uint8_t* outPointer);
public:
virtual ~CamstudioCodec();
virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) override;
virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override;
virtual const char* GetFourCC() override;
};

View file

@ -12,7 +12,7 @@ private:
uint8_t* _buffer = nullptr; uint8_t* _buffer = nullptr;
public: public:
virtual bool SetupCompress(int width, int height) override virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) override
{ {
_height = height; _height = height;
_width = width; _width = width;

View file

@ -324,6 +324,7 @@
<ClInclude Include="ArchiveReader.h" /> <ClInclude Include="ArchiveReader.h" />
<ClInclude Include="AviWriter.h" /> <ClInclude Include="AviWriter.h" />
<ClInclude Include="blip_buf.h" /> <ClInclude Include="blip_buf.h" />
<ClInclude Include="CamstudioCodec.h" />
<ClInclude Include="CRC32.h" /> <ClInclude Include="CRC32.h" />
<ClInclude Include="FolderUtilities.h" /> <ClInclude Include="FolderUtilities.h" />
<ClInclude Include="HexUtilities.h" /> <ClInclude Include="HexUtilities.h" />
@ -363,6 +364,7 @@
<ClCompile Include="ArchiveReader.cpp" /> <ClCompile Include="ArchiveReader.cpp" />
<ClCompile Include="AviWriter.cpp" /> <ClCompile Include="AviWriter.cpp" />
<ClCompile Include="blip_buf.cpp" /> <ClCompile Include="blip_buf.cpp" />
<ClCompile Include="CamstudioCodec.cpp" />
<ClCompile Include="CRC32.cpp" /> <ClCompile Include="CRC32.cpp" />
<ClCompile Include="FolderUtilities.cpp" /> <ClCompile Include="FolderUtilities.cpp" />
<ClCompile Include="HexUtilities.cpp" /> <ClCompile Include="HexUtilities.cpp" />

View file

@ -137,6 +137,9 @@
<ClInclude Include="RawCodec.h"> <ClInclude Include="RawCodec.h">
<Filter>Avi</Filter> <Filter>Avi</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="CamstudioCodec.h">
<Filter>Avi</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
@ -241,5 +244,8 @@
<ClCompile Include="AviWriter.cpp"> <ClCompile Include="AviWriter.cpp">
<Filter>Avi</Filter> <Filter>Avi</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="CamstudioCodec.cpp">
<Filter>Avi</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -221,12 +221,12 @@ void ZmbvCodec::AddXorFrame(void) {
} }
} }
bool ZmbvCodec::SetupCompress( int _width, int _height ) { bool ZmbvCodec::SetupCompress( int _width, int _height, uint32_t compressionLevel ) {
width = _width; width = _width;
height = _height; height = _height;
pitch = _width + 2*MAX_VECTOR; pitch = _width + 2*MAX_VECTOR;
format = ZMBV_FORMAT_NONE; format = ZMBV_FORMAT_NONE;
if (deflateInit (&zstream, 4) != Z_OK) if (deflateInit (&zstream, compressionLevel) != Z_OK)
return false; return false;
return true; return true;

View file

@ -109,7 +109,7 @@ private:
public: public:
ZmbvCodec(); ZmbvCodec();
bool SetupCompress(int _width, int _height) override; bool SetupCompress(int _width, int _height, uint32_t compressionLevel) override;
int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override; int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override;
const char* GetFourCC() override; const char* GetFourCC() override;
}; };