diff --git a/Core/AviRecorder.cpp b/Core/AviRecorder.cpp index 9e79598d..ec16f9f7 100644 --- a/Core/AviRecorder.cpp +++ b/Core/AviRecorder.cpp @@ -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; } diff --git a/Core/AviRecorder.h b/Core/AviRecorder.h index a82017a4..c61cec14 100644 --- a/Core/AviRecorder.h +++ b/Core/AviRecorder.h @@ -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); diff --git a/Core/VideoDecoder.cpp b/Core/VideoDecoder.cpp index fda58164..66f63054 100644 --- a/Core/VideoDecoder.cpp +++ b/Core/VideoDecoder.cpp @@ -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 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; } } diff --git a/Core/VideoDecoder.h b/Core/VideoDecoder.h index 2545e610..73aa0f4a 100644 --- a/Core/VideoDecoder.h +++ b/Core/VideoDecoder.h @@ -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(); diff --git a/GUI.NET/Config/AviRecordInfo.cs b/GUI.NET/Config/AviRecordInfo.cs new file mode 100644 index 00000000..b042a4a0 --- /dev/null +++ b/GUI.NET/Config/AviRecordInfo.cs @@ -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; + } +} diff --git a/GUI.NET/Config/Configuration.cs b/GUI.NET/Config/Configuration.cs index 8c0440f6..c5a026f7 100644 --- a/GUI.NET/Config/Configuration.cs +++ b/GUI.NET/Config/Configuration.cs @@ -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(); VsConfig = new List(); DebugInfo = new DebugInfo(); + AviRecordInfo = new AviRecordInfo(); } ~Configuration() diff --git a/GUI.NET/Dependencies/resources.en.xml b/GUI.NET/Dependencies/resources.en.xml index 0a96add7..ce8924cf 100644 --- a/GUI.NET/Dependencies/resources.en.xml +++ b/GUI.NET/Dependencies/resources.en.xml @@ -166,5 +166,10 @@ Not equal Greater + + None (Uncompressed) + Zip Motion Block Video (ZMBV) + Camstudio (CSCD) + \ No newline at end of file diff --git a/GUI.NET/Dependencies/resources.es.xml b/GUI.NET/Dependencies/resources.es.xml index 796edfc5..e4f934cb 100644 --- a/GUI.NET/Dependencies/resources.es.xml +++ b/GUI.NET/Dependencies/resources.es.xml @@ -482,7 +482,10 @@
Save to: - Use ZMBV compression + Video Codec: + Compression Level: + low (fast) + high (slow) Browse... OK Cancelar @@ -652,5 +655,10 @@ Español Українська + + None (Uncompressed) + Zip Motion Block Video (ZMBV) + Camstudio (CSCD) + \ No newline at end of file diff --git a/GUI.NET/Dependencies/resources.fr.xml b/GUI.NET/Dependencies/resources.fr.xml index c5be65b8..b3023b17 100644 --- a/GUI.NET/Dependencies/resources.fr.xml +++ b/GUI.NET/Dependencies/resources.fr.xml @@ -495,7 +495,10 @@
Enregistrer sous: - Utiliser la compression ZMBV + Codec vidéo : + Niveau de compression : + faible (rapide) + élevé (lent) Parcourir... OK Annuler @@ -667,5 +670,10 @@ Pas égale Plus grande + + Aucun (Vidéo non-compressé) + Zip Motion Block Video (ZMBV) + Camstudio (CSCD) + \ No newline at end of file diff --git a/GUI.NET/Dependencies/resources.ja.xml b/GUI.NET/Dependencies/resources.ja.xml index af390c65..3297135b 100644 --- a/GUI.NET/Dependencies/resources.ja.xml +++ b/GUI.NET/Dependencies/resources.ja.xml @@ -477,7 +477,10 @@
保存先: - ZMBV圧縮を利用する + ビデオコーデック: + 圧縮レベル: + 低い (早い) + 高い (遅い) 参照... OK キャンセル @@ -649,5 +652,10 @@ とは違う より大きい + + 圧縮なし + Zip Motion Block Video (ZMBV) + Camstudio (CSCD) + \ No newline at end of file diff --git a/GUI.NET/Dependencies/resources.pt.xml b/GUI.NET/Dependencies/resources.pt.xml index fa2e1395..a7d07b07 100644 --- a/GUI.NET/Dependencies/resources.pt.xml +++ b/GUI.NET/Dependencies/resources.pt.xml @@ -482,7 +482,10 @@
Save to: - Use ZMBV compression + Video Codec: + Compression Level: + low (fast) + high (slow) Browse... OK Cancelar @@ -652,5 +655,10 @@ Español Українська + + None (Uncompressed) + Zip Motion Block Video (ZMBV) + Camstudio (CSCD) + diff --git a/GUI.NET/Dependencies/resources.ru.xml b/GUI.NET/Dependencies/resources.ru.xml index 32f4aeeb..7c098634 100644 --- a/GUI.NET/Dependencies/resources.ru.xml +++ b/GUI.NET/Dependencies/resources.ru.xml @@ -486,7 +486,10 @@
Save to: - Use ZMBV compression + Video Codec: + Compression Level: + low (fast) + high (slow) Browse... OK Отмена @@ -658,5 +661,10 @@ Не равно Больше + + None (Uncompressed) + Zip Motion Block Video (ZMBV) + Camstudio (CSCD) + \ No newline at end of file diff --git a/GUI.NET/Dependencies/resources.uk.xml b/GUI.NET/Dependencies/resources.uk.xml index 6e8b6741..798cc9ca 100644 --- a/GUI.NET/Dependencies/resources.uk.xml +++ b/GUI.NET/Dependencies/resources.uk.xml @@ -485,7 +485,10 @@
Save to: - Use ZMBV compression + Video Codec: + Compression Level: + low (fast) + high (slow) Browse... OK Вiдмiна @@ -657,5 +660,10 @@ Не дорівнює Бiльше + + None (Uncompressed) + Zip Motion Block Video (ZMBV) + Camstudio (CSCD) + diff --git a/GUI.NET/Forms/frmMain.cs b/GUI.NET/Forms/frmMain.cs index 91609ddb..41463308 100644 --- a/GUI.NET/Forms/frmMain.cs +++ b/GUI.NET/Forms/frmMain.cs @@ -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); } } } diff --git a/GUI.NET/Forms/frmRecordAvi.Designer.cs b/GUI.NET/Forms/frmRecordAvi.Designer.cs index e6bd6a8b..4395f14f 100644 --- a/GUI.NET/Forms/frmRecordAvi.Designer.cs +++ b/GUI.NET/Forms/frmRecordAvi.Designer.cs @@ -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; } } \ No newline at end of file diff --git a/GUI.NET/Forms/frmRecordAvi.cs b/GUI.NET/Forms/frmRecordAvi.cs index 4f5e434e..0863862f 100644 --- a/GUI.NET/Forms/frmRecordAvi.cs +++ b/GUI.NET/Forms/frmRecordAvi.cs @@ -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; + } } } diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj index 5bb81167..7ccaad72 100644 --- a/GUI.NET/GUI.NET.csproj +++ b/GUI.NET/GUI.NET.csproj @@ -205,6 +205,7 @@ + diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index d3f7fbd9..6f10c2ce 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -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 diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 6e12c91e..32820e23 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -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(); } diff --git a/Utilities/AviWriter.cpp b/Utilities/AviWriter.cpp index 3349b2c7..fdd63fce 100644 --- a/Utilities/AviWriter.cpp +++ b/Utilities/AviWriter.cpp @@ -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; } diff --git a/Utilities/AviWriter.h b/Utilities/AviWriter.h index f0691bd8..3941c9c4 100644 --- a/Utilities/AviWriter.h +++ b/Utilities/AviWriter.h @@ -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(); }; \ No newline at end of file diff --git a/Utilities/BaseCodec.h b/Utilities/BaseCodec.h index cc1ea691..47d83283 100644 --- a/Utilities/BaseCodec.h +++ b/Utilities/BaseCodec.h @@ -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; }; \ No newline at end of file diff --git a/Utilities/CamstudioCodec.cpp b/Utilities/CamstudioCodec.cpp new file mode 100644 index 00000000..890c8867 --- /dev/null +++ b/Utilities/CamstudioCodec.cpp @@ -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"; +} \ No newline at end of file diff --git a/Utilities/CamstudioCodec.h b/Utilities/CamstudioCodec.h new file mode 100644 index 00000000..45f1fcb9 --- /dev/null +++ b/Utilities/CamstudioCodec.h @@ -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; +}; \ No newline at end of file diff --git a/Utilities/RawCodec.h b/Utilities/RawCodec.h index 2eff5d4c..ea328995 100644 --- a/Utilities/RawCodec.h +++ b/Utilities/RawCodec.h @@ -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; diff --git a/Utilities/Utilities.vcxproj b/Utilities/Utilities.vcxproj index 5feaaeba..38dc983b 100644 --- a/Utilities/Utilities.vcxproj +++ b/Utilities/Utilities.vcxproj @@ -324,6 +324,7 @@ + @@ -363,6 +364,7 @@ + diff --git a/Utilities/Utilities.vcxproj.filters b/Utilities/Utilities.vcxproj.filters index 1433f4f0..2817c695 100644 --- a/Utilities/Utilities.vcxproj.filters +++ b/Utilities/Utilities.vcxproj.filters @@ -137,6 +137,9 @@ Avi + + Avi + @@ -241,5 +244,8 @@ Avi + + Avi + \ No newline at end of file diff --git a/Utilities/ZmbvCodec.cpp b/Utilities/ZmbvCodec.cpp index dbdde397..9fe112d2 100644 --- a/Utilities/ZmbvCodec.cpp +++ b/Utilities/ZmbvCodec.cpp @@ -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; diff --git a/Utilities/ZmbvCodec.h b/Utilities/ZmbvCodec.h index bdb27c40..5e3c2858 100644 --- a/Utilities/ZmbvCodec.h +++ b/Utilities/ZmbvCodec.h @@ -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; };