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) {
_outputFile = filename;
@ -32,7 +32,7 @@ bool AviRecorder::StartRecording(string filename, VideoCodec codec, uint32_t wid
_frameBuffer = new uint8_t[_frameBufferLength];
_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();
return false;
}

View file

@ -26,7 +26,7 @@ public:
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 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) {
shared_ptr<AviRecorder> recorder(new AviRecorder());
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;
}
}

View file

@ -70,7 +70,7 @@ public:
void StartThread();
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 StopRecording();
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 PlayerProfile Profile;
public DebugInfo DebugInfo;
public AviRecordInfo AviRecordInfo;
public Configuration()
{
@ -43,6 +44,7 @@ namespace Mesen.GUI.Config
Cheats = new List<CheatInfo>();
VsConfig = new List<VsConfigInfo>();
DebugInfo = new DebugInfo();
AviRecordInfo = new AviRecordInfo();
}
~Configuration()

View file

@ -166,5 +166,10 @@
<Value ID="NotEqual">Not equal</Value>
<Value ID="Greater">Greater</Value>
</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>
</Resources>

View file

@ -482,7 +482,10 @@
</Form>
<Form ID="frmRecordAvi" Title="Video Recorder">
<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="btnOK">OK</Control>
<Control ID="btnCancel">Cancelar</Control>
@ -652,5 +655,10 @@
<Value ID="Spanish">Español</Value>
<Value ID="Ukrainian">Українська</Value>
</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>
</Resources>

View file

@ -495,7 +495,10 @@
</Form>
<Form ID="frmRecordAvi" Title="Enregistreur vidéo">
<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="btnOK">OK</Control>
<Control ID="btnCancel">Annuler</Control>
@ -667,5 +670,10 @@
<Value ID="NotEqual">Pas égale</Value>
<Value ID="Greater">Plus grande</Value>
</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>
</Resources>

View file

@ -477,7 +477,10 @@
</Form>
<Form ID="frmRecordAvi" Title="動画レコーダー">
<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="btnOK">OK</Control>
<Control ID="btnCancel">キャンセル</Control>
@ -649,5 +652,10 @@
<Value ID="NotEqual">とは違う</Value>
<Value ID="Greater">より大きい</Value>
</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>
</Resources>

View file

@ -482,7 +482,10 @@
</Form>
<Form ID="frmRecordAvi" Title="Video Recorder">
<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="btnOK">OK</Control>
<Control ID="btnCancel">Cancelar</Control>
@ -652,5 +655,10 @@
<Value ID="Spanish">Español</Value>
<Value ID="Ukrainian">Українська</Value>
</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>
</Resources>

View file

@ -486,7 +486,10 @@
</Form>
<Form ID="frmRecordAvi" Title="Video Recorder">
<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="btnOK">OK</Control>
<Control ID="btnCancel">Отмена</Control>
@ -658,5 +661,10 @@
<Value ID="NotEqual">Не равно</Value>
<Value ID="Greater">Больше</Value>
</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>
</Resources>

View file

@ -485,7 +485,10 @@
</Form>
<Form ID="frmRecordAvi" Title="Video Recorder">
<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="btnOK">OK</Control>
<Control ID="btnCancel">Вiдмiна</Control>
@ -657,5 +660,10 @@
<Value ID="NotEqual">Не дорівнює</Value>
<Value ID="Greater">Бiльше</Value>
</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>
</Resources>

View file

@ -956,7 +956,7 @@ namespace Mesen.GUI.Forms
{
using(frmRecordAvi frm = new frmRecordAvi()) {
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()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.lblCodec = new System.Windows.Forms.Label();
this.lblAviFile = new System.Windows.Forms.Label();
this.txtFilename = new System.Windows.Forms.TextBox();
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.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trkCompressionLevel)).BeginInit();
this.tlpCompressionLevel.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 66);
this.baseConfigPanel.Size = new System.Drawing.Size(375, 29);
this.baseConfigPanel.Location = new System.Drawing.Point(0, 99);
this.baseConfigPanel.Size = new System.Drawing.Size(397, 29);
//
// tableLayoutPanel1
//
@ -46,21 +56,34 @@
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());
this.tableLayoutPanel1.Controls.Add(this.lblCodec, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.lblAviFile, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.txtFilename, 1, 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.Location = new System.Drawing.Point(0, 0);
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(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(375, 95);
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(397, 128);
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
//
this.lblAviFile.Anchor = System.Windows.Forms.AnchorStyles.Left;
@ -74,15 +97,15 @@
// txtFilename
//
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.ReadOnly = true;
this.txtFilename.Size = new System.Drawing.Size(235, 20);
this.txtFilename.Size = new System.Drawing.Size(205, 20);
this.txtFilename.TabIndex = 1;
//
// 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.Size = new System.Drawing.Size(75, 23);
this.btnBrowse.TabIndex = 2;
@ -90,25 +113,98 @@
this.btnBrowse.UseVisualStyleBackColor = true;
this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
//
// chkUseCompression
// cboVideoCodec
//
this.chkUseCompression.AutoSize = true;
this.chkUseCompression.Checked = true;
this.chkUseCompression.CheckState = System.Windows.Forms.CheckState.Checked;
this.tableLayoutPanel1.SetColumnSpan(this.chkUseCompression, 3);
this.chkUseCompression.Location = new System.Drawing.Point(3, 32);
this.chkUseCompression.Name = "chkUseCompression";
this.chkUseCompression.Size = new System.Drawing.Size(140, 17);
this.chkUseCompression.TabIndex = 3;
this.chkUseCompression.Text = "Use ZMBV compression";
this.chkUseCompression.UseVisualStyleBackColor = true;
this.cboVideoCodec.Dock = System.Windows.Forms.DockStyle.Fill;
this.cboVideoCodec.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboVideoCodec.FormattingEnabled = true;
this.cboVideoCodec.Location = new System.Drawing.Point(108, 32);
this.cboVideoCodec.Name = "cboVideoCodec";
this.cboVideoCodec.Size = new System.Drawing.Size(205, 21);
this.cboVideoCodec.TabIndex = 4;
this.cboVideoCodec.SelectedIndexChanged += new System.EventHandler(this.cboVideoCodec_SelectedIndexChanged);
//
// 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
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
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.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "frmRecordAvi";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Video Recording Options";
@ -116,6 +212,11 @@
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
this.tableLayoutPanel1.ResumeLayout(false);
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);
}
@ -126,6 +227,13 @@
private System.Windows.Forms.Label lblAviFile;
private System.Windows.Forms.TextBox txtFilename;
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()
{
InitializeComponent();
Entity = ConfigManager.Config.AviRecordInfo;
AddBinding("Codec", cboVideoCodec);
AddBinding("CompressionLevel", trkCompressionLevel);
}
public string Filename { get; internal set; }
public bool UseCompression { get; internal set; }
protected override bool ValidateInput()
{
@ -31,7 +34,6 @@ namespace Mesen.GUI.Forms
base.OnFormClosed(e);
this.Filename = txtFilename.Text;
this.UseCompression = chkUseCompression.Checked;
}
private void btnBrowse_Click(object sender, EventArgs e)
@ -44,5 +46,11 @@ namespace Mesen.GUI.Forms
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>
</ItemGroup>
<ItemGroup>
<Compile Include="Config\AviRecordInfo.cs" />
<Compile Include="Config\DebugInfo.cs" />
<Compile Include="Config\EmulationInfo.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 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)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool AviIsRecording();
@ -1092,6 +1092,7 @@ namespace Mesen.GUI
{
None = 0,
ZMBV = 1,
CSCD = 2,
}
public enum VideoFilterType

View file

@ -300,7 +300,7 @@ namespace InteropEmu {
DllExport bool __stdcall MoviePlaying() { return Movie::Playing(); }
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 bool __stdcall AviIsRecording() { return VideoDecoder::GetInstance()->IsRecording(); }

View file

@ -26,6 +26,7 @@
#include "BaseCodec.h"
#include "RawCodec.h"
#include "ZmbvCodec.h"
#include "CamstudioCodec.h"
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;
}
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;
_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;
}
if(_codecType == VideoCodec::ZMBV) {
_codec.reset(new ZmbvCodec());
} else {
_codec.reset(new RawCodec());
switch(_codecType) {
default:
case VideoCodec::None: _codec.reset(new RawCodec()); break;
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;
}

View file

@ -10,6 +10,7 @@ enum class VideoCodec
{
None = 0,
ZMBV = 1,
CSCD = 2,
};
class AviWriter
@ -50,6 +51,6 @@ public:
void AddFrame(uint8_t* frameData);
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();
};

View file

@ -4,7 +4,7 @@
class BaseCodec
{
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 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;
public:
virtual bool SetupCompress(int width, int height) override
virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) override
{
_height = height;
_width = width;

View file

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

View file

@ -137,6 +137,9 @@
<ClInclude Include="RawCodec.h">
<Filter>Avi</Filter>
</ClInclude>
<ClInclude Include="CamstudioCodec.h">
<Filter>Avi</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -241,5 +244,8 @@
<ClCompile Include="AviWriter.cpp">
<Filter>Avi</Filter>
</ClCompile>
<ClCompile Include="CamstudioCodec.cpp">
<Filter>Avi</Filter>
</ClCompile>
</ItemGroup>
</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;
height = _height;
pitch = _width + 2*MAX_VECTOR;
format = ZMBV_FORMAT_NONE;
if (deflateInit (&zstream, 4) != Z_OK)
if (deflateInit (&zstream, compressionLevel) != Z_OK)
return false;
return true;

View file

@ -109,7 +109,7 @@ private:
public:
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;
const char* GetFourCC() override;
};