summaryrefslogtreecommitdiffstats
path: root/win/CS/HandBrake.Interop/HandBrakeInterop
diff options
context:
space:
mode:
authorsr55 <[email protected]>2011-06-12 16:54:23 +0000
committersr55 <[email protected]>2011-06-12 16:54:23 +0000
commit399ab292d7feddf5e83be866caafbaef634eca87 (patch)
tree519a29f631a5d07c25e4b01ef195005d166ddad6 /win/CS/HandBrake.Interop/HandBrakeInterop
parent191aad2ed1e77d8292f72ab7caf8996d117edd63 (diff)
WinGui: Bring in the HandBrake Interop library written by RandomEngy.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4045 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'win/CS/HandBrake.Interop/HandBrakeInterop')
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs110
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/EncodeCompletedEventArgs.cs12
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/EncodeProgressEventArgs.cs20
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs1600
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj206
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs254
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs237
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs415
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs99
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_audio.cs120
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_chapter_s.cs48
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_handle_s.cs78
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs149
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_subtitle.cs122
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_title_s.cs145
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs144
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Language.cs38
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/LanguageCodes.cs255
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/MarshalingConstants.cs18
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/MessageLoggedEventArgs.cs12
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Cropping.cs26
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/EncodeJob.cs83
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Anamorphic.cs20
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs32
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoding.cs34
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Decomb.cs14
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Deinterlace.cs16
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Denoise.cs16
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Detelecine.cs14
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/EncodingProfile.cs113
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Mixdown.cs29
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputExtension.cs13
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputFormat.cs17
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncodeRateType.cs14
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs20
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Limits.cs14
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Size.cs19
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceSubtitle.cs29
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceType.cs10
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/SrtSubtitle.cs28
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/Subtitles.cs13
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Model/VideoRangeType.cs20
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/NativeList.cs34
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs36
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/ScanProgressEventArgs.cs13
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs17
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioTrack.cs90
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Chapter.cs38
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/InputType.cs20
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Subtitle.cs54
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleSource.cs18
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleType.cs13
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Title.cs144
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/Utilities.cs32
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/libgcc_s_sjlj-1.dllbin0 -> 241655 bytes
55 files changed, 5185 insertions, 0 deletions
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs
new file mode 100644
index 000000000..691c97701
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HandBrake.SourceData;
+
+namespace HandBrake.Interop
+{
+ public static class Converters
+ {
+ private static Dictionary<double, int> vrates = new Dictionary<double, int>
+ {
+ {5, 5400000},
+ {10, 2700000},
+ {12, 2250000},
+ {15, 1800000},
+ {23.976, 1126125},
+ {24, 1125000},
+ {25, 1080000},
+ {29.97, 900900}
+ };
+
+ public static int FramerateToVrate(double framerate)
+ {
+ if (!vrates.ContainsKey(framerate))
+ {
+ throw new ArgumentException("Framerate not recognized.", "framerate");
+ }
+
+ return vrates[framerate];
+ }
+
+ public static int MixdownToNative(Mixdown mixdown)
+ {
+ if (mixdown == Mixdown.Auto)
+ {
+ throw new ArgumentException("Cannot convert Auto to native.");
+ }
+
+ switch (mixdown)
+ {
+ case Mixdown.DolbyProLogicII:
+ return NativeConstants.HB_AMIXDOWN_DOLBYPLII;
+ case Mixdown.DolbySurround:
+ return NativeConstants.HB_AMIXDOWN_DOLBY;
+ case Mixdown.Mono:
+ return NativeConstants.HB_AMIXDOWN_MONO;
+ case Mixdown.SixChannelDiscrete:
+ return NativeConstants.HB_AMIXDOWN_6CH;
+ case Mixdown.Stereo:
+ return NativeConstants.HB_AMIXDOWN_STEREO;
+ }
+
+ return 0;
+ }
+
+ public static Mixdown NativeToMixdown(int mixdown)
+ {
+ switch (mixdown)
+ {
+ case NativeConstants.HB_AMIXDOWN_MONO:
+ return Mixdown.Mono;
+ case NativeConstants.HB_AMIXDOWN_STEREO:
+ return Mixdown.Stereo;
+ case NativeConstants.HB_AMIXDOWN_DOLBY:
+ return Mixdown.DolbySurround;
+ case NativeConstants.HB_AMIXDOWN_DOLBYPLII:
+ return Mixdown.DolbyProLogicII;
+ case NativeConstants.HB_AMIXDOWN_6CH:
+ return Mixdown.SixChannelDiscrete;
+ }
+
+ throw new ArgumentException("Unrecognized mixdown: " + mixdown, "mixdown");
+ }
+
+ public static uint AudioEncoderToNative(AudioEncoder encoder)
+ {
+ switch (encoder)
+ {
+ case AudioEncoder.Ac3Passthrough:
+ return NativeConstants.HB_ACODEC_AC3_PASS;
+ case AudioEncoder.DtsPassthrough:
+ return NativeConstants.HB_ACODEC_DCA_PASS;
+ case AudioEncoder.Faac:
+ return NativeConstants.HB_ACODEC_FAAC;
+ case AudioEncoder.Lame:
+ return NativeConstants.HB_ACODEC_LAME;
+ case AudioEncoder.Ac3:
+ return NativeConstants.HB_ACODEC_AC3;
+ case AudioEncoder.Vorbis:
+ return NativeConstants.HB_ACODEC_VORBIS;
+ }
+
+ return 0;
+ }
+
+ public static AudioCodec NativeToAudioCodec(uint codec)
+ {
+ switch (codec)
+ {
+ case NativeConstants.HB_ACODEC_AC3:
+ return AudioCodec.Ac3;
+ case NativeConstants.HB_ACODEC_DCA:
+ return AudioCodec.Dts;
+ default:
+ return AudioCodec.Other;
+ }
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/EncodeCompletedEventArgs.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/EncodeCompletedEventArgs.cs
new file mode 100644
index 000000000..f35a449a1
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/EncodeCompletedEventArgs.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class EncodeCompletedEventArgs : EventArgs
+ {
+ public bool Error { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/EncodeProgressEventArgs.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/EncodeProgressEventArgs.cs
new file mode 100644
index 000000000..484ea7b7b
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/EncodeProgressEventArgs.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class EncodeProgressEventArgs : EventArgs
+ {
+ public float FractionComplete { get; set; }
+ public float CurrentFrameRate { get; set; }
+ public float AverageFrameRate { get; set; }
+ public TimeSpan EstimatedTimeLeft { get; set; }
+
+ /// <summary>
+ /// Gets or sets the current encoding pass. (-1: subtitle scan, 1: first pass, 2: second pass)
+ /// </summary>
+ public int Pass { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs
new file mode 100644
index 000000000..1d8d63a2e
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs
@@ -0,0 +1,1600 @@
+namespace HandBrake.Interop
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Runtime.InteropServices;
+ using System.Text;
+ using System.Timers;
+ using System.Threading;
+ using System.Windows.Media.Imaging;
+ using HandBrake.SourceData;
+ using HandBrake.Interop;
+
+ /// <summary>
+ /// A wrapper for a HandBrake instance.
+ /// </summary>
+ public class HandBrakeInstance : IDisposable
+ {
+ /// <summary>
+ /// The modulus for picture size when auto-sizing dimensions.
+ /// </summary>
+ private const int PictureAutoSizeModulus = 2;
+
+ /// <summary>
+ /// Modulus used for picture size when using non-anamorphic.
+ /// </summary>
+ private const int NonAnamorphicAutoSizeModulus = 16;
+
+ /// <summary>
+ /// The number of MS between status polls when scanning.
+ /// </summary>
+ private const double ScanPollIntervalMs = 200;
+
+ /// <summary>
+ /// The number of MS between status polls when encoding.
+ /// </summary>
+ private const double EncodePollIntervalMs = 200;
+
+ /// <summary>
+ /// X264 options to add for a turbo first pass.
+ /// </summary>
+ private const string TurboX264Opts = "ref=1:subme=2:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0";
+
+ /// <summary>
+ /// Default value to give as a minimum duration when scanning.
+ /// </summary>
+ private const ulong DefaultMinDuration = 900000;
+
+ /// <summary>
+ /// The native handle to the HandBrake instance.
+ /// </summary>
+ private IntPtr hbHandle;
+
+ /// <summary>
+ /// The number of previews created during scan.
+ /// </summary>
+ private int previewCount;
+
+ /// <summary>
+ /// The timer to poll for scan status.
+ /// </summary>
+ private System.Timers.Timer scanPollTimer;
+
+ /// <summary>
+ /// The timer to poll for encode status.
+ /// </summary>
+ private System.Timers.Timer encodePollTimer;
+
+ /// <summary>
+ /// The list of original titles in native structure form.
+ /// </summary>
+ private List<hb_title_s> originalTitles;
+
+ /// <summary>
+ /// The list of titles on this instance.
+ /// </summary>
+ private List<Title> titles;
+
+ /// <summary>
+ /// The current encode job for this instance.
+ /// </summary>
+ private EncodeJob currentJob;
+
+ /// <summary>
+ /// True if the current job is scanning for subtitles.
+ /// </summary>
+ private bool subtitleScan;
+
+ /// <summary>
+ /// The index of the default title.
+ /// </summary>
+ private int featureTitle;
+
+ /// <summary>
+ /// A list of native memory locations allocated by this instance.
+ /// </summary>
+ private List<IntPtr> encodeAllocatedMemory;
+
+ /// <summary>
+ /// Fires for progress updates when scanning.
+ /// </summary>
+ public event EventHandler<ScanProgressEventArgs> ScanProgress;
+
+ /// <summary>
+ /// Fires when a scan has completed.
+ /// </summary>
+ public event EventHandler<EventArgs> ScanCompleted;
+
+ /// <summary>
+ /// Fires for progress updates when encoding.
+ /// </summary>
+ public event EventHandler<EncodeProgressEventArgs> EncodeProgress;
+
+ /// <summary>
+ /// Fires when an encode has completed.
+ /// </summary>
+ public event EventHandler<EncodeCompletedEventArgs> EncodeCompleted;
+
+ /// <summary>
+ /// Destructor.
+ /// </summary>
+ ~HandBrakeInstance()
+ {
+ this.Dispose(false);
+ }
+
+ /// <summary>
+ /// The list of titles on this instance.
+ /// </summary>
+ public List<Title> Titles
+ {
+ get
+ {
+ return this.titles;
+ }
+ }
+
+ /// <summary>
+ /// The number of previews created during scan.
+ /// </summary>
+ public int PreviewCount
+ {
+ get
+ {
+ return this.previewCount;
+ }
+ }
+
+ /// <summary>
+ /// Gets the index of the default title.
+ /// </summary>
+ public int FeatureTitle
+ {
+ get
+ {
+ return this.featureTitle;
+ }
+ }
+
+ /// <summary>
+ /// Initializes this instance.
+ /// </summary>
+ /// <param name="verbosity"></param>
+ public void Initialize(int verbosity)
+ {
+ HandBrakeUtils.RegisterLogger();
+ this.hbHandle = HBFunctions.hb_init(verbosity, update_check: 0);
+ }
+
+ /// <summary>
+ /// Starts scanning the given path.
+ /// </summary>
+ /// <param name="path">The path to the video to scan.</param>
+ /// <param name="previewCount">The number of preview images to make.</param>
+ public void StartScan(string path, int previewCount)
+ {
+ this.StartScan(path, previewCount, 0);
+ }
+
+ /// <summary>
+ /// Starts a scan of the given path.
+ /// </summary>
+ /// <param name="path">The path of the video to scan.</param>
+ /// <param name="previewCount">The number of previews to make on each title.</param>
+ /// <param name="titleIndex">The title index to scan (1-based, 0 for all titles).</param>
+ public void StartScan(string path, int previewCount, int titleIndex)
+ {
+ this.previewCount = previewCount;
+ HBFunctions.hb_scan(this.hbHandle, path, titleIndex, previewCount, 1, DefaultMinDuration);
+ this.scanPollTimer = new System.Timers.Timer();
+ this.scanPollTimer.Interval = ScanPollIntervalMs;
+
+ // Lambda notation used to make sure we can view any JIT exceptions the method throws
+ this.scanPollTimer.Elapsed += (o, e) =>
+ {
+ this.PollScanProgress();
+ };
+ this.scanPollTimer.Start();
+ }
+
+ /// <summary>
+ /// Stops an ongoing scan.
+ /// </summary>
+ public void StopScan()
+ {
+ HBFunctions.hb_scan_stop(this.hbHandle);
+ }
+
+ /// <summary>
+ /// Gets an image for the given job and preview
+ /// </summary>
+ /// <remarks>
+ /// Only incorporates sizing and aspect ratio into preview image.
+ /// </remarks>
+ /// <param name="job">The encode job to preview.</param>
+ /// <param name="previewNumber">The index of the preview to get (0-based).</param>
+ /// <returns>An image with the requested preview.</returns>
+ public BitmapImage GetPreview(EncodeJob job, int previewNumber)
+ {
+ hb_title_s title = this.GetOriginalTitle(job.Title);
+
+ hb_job_s nativeJob = InteropUtilities.ReadStructure<hb_job_s>(title.job);
+ List<IntPtr> allocatedMemory = this.ApplyJob(ref nativeJob, job);
+
+ // There are some problems with getting previews with deinterlacing. Disabling for now.
+ nativeJob.deinterlace = 0;
+
+ // Create a new job pointer from our modified job object
+ IntPtr newJob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_job_s)));
+ Marshal.StructureToPtr(nativeJob, newJob, false);
+ allocatedMemory.Add(newJob);
+
+ int outputWidth = nativeJob.width;
+ int outputHeight = nativeJob.height;
+ int imageBufferSize = outputWidth * outputHeight * 4;
+ IntPtr nativeBuffer = Marshal.AllocHGlobal(imageBufferSize);
+ allocatedMemory.Add(nativeBuffer);
+ HBFunctions.hb_set_job(this.hbHandle, job.Title, ref nativeJob);
+ HBFunctions.hb_get_preview_by_index(this.hbHandle, job.Title, previewNumber, nativeBuffer);
+
+ // Copy the filled image buffer to a managed array.
+ byte[] managedBuffer = new byte[imageBufferSize];
+ Marshal.Copy(nativeBuffer, managedBuffer, 0, imageBufferSize);
+
+ InteropUtilities.FreeMemory(allocatedMemory);
+
+ var bitmap = new System.Drawing.Bitmap(outputWidth, outputHeight);
+ System.Drawing.Imaging.BitmapData bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, outputWidth, outputHeight), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
+
+ IntPtr ptr = bitmapData.Scan0;
+
+ for (int i = 0; i < nativeJob.height; i++)
+ {
+ Marshal.Copy(managedBuffer, i * nativeJob.width * 4, ptr, nativeJob.width * 4);
+ ptr = IntPtr.Add(ptr, bitmapData.Stride);
+ }
+
+ bitmap.UnlockBits(bitmapData);
+
+ using (var memoryStream = new MemoryStream())
+ {
+ try
+ {
+ bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
+ }
+ finally
+ {
+ bitmap.Dispose();
+ }
+
+ var wpfBitmap = new BitmapImage();
+ wpfBitmap.BeginInit();
+ wpfBitmap.CacheOption = BitmapCacheOption.OnLoad;
+ wpfBitmap.StreamSource = memoryStream;
+ wpfBitmap.EndInit();
+ wpfBitmap.Freeze();
+
+ return wpfBitmap;
+ }
+ }
+
+ /// <summary>
+ /// Calculates the video bitrate for the given job and target size.
+ /// </summary>
+ /// <param name="job">The encode job.</param>
+ /// <param name="sizeMB">The target size in MB.</param>
+ /// <param name="overallSelectedLengthSeconds">The currently selected encode length. Used in preview
+ /// for calculating bitrate when the target size would be wrong.</param>
+ /// <returns>The video bitrate in kbps.</returns>
+ public int CalculateBitrate(EncodeJob job, int sizeMB, double overallSelectedLengthSeconds = 0)
+ {
+ long availableBytes = ((long) sizeMB) * 1024 * 1024;
+
+ EncodingProfile profile = job.EncodingProfile;
+ Title title = this.GetTitle(job.Title);
+
+ double lengthSeconds = overallSelectedLengthSeconds > 0 ? overallSelectedLengthSeconds : HandBrakeUtils.GetJobLengthSeconds(job, title);
+ lengthSeconds += 1.5;
+
+ double outputFramerate;
+ if (profile.Framerate == 0)
+ {
+ outputFramerate = title.Framerate;
+ }
+ else
+ {
+ // Not sure what to do for VFR here hb_calc_bitrate never handled it...
+ // just use the peak for now.
+ outputFramerate = profile.Framerate;
+ }
+
+ long frames = (long)(lengthSeconds * outputFramerate);
+
+ availableBytes -= frames * HandBrakeUtils.ContainerOverheadPerFrame;
+
+ List<Tuple<AudioEncoding, int>> outputTrackList = this.GetOutputTracks(job, title);
+ availableBytes -= HandBrakeUtils.GetAudioSize(job, lengthSeconds, title, outputTrackList);
+
+ if (availableBytes < 0)
+ {
+ return 0;
+ }
+
+ // Video bitrate is in kilobits per second, or where 1 kbps is 1000 bits per second.
+ // So 1 kbps is 125 bytes per second.
+ return (int)(availableBytes / (125 * lengthSeconds));
+ }
+
+ /// <summary>
+ /// Gives estimated file size (in MB) of the given job and video bitrate.
+ /// </summary>
+ /// <param name="job">The encode job.</param>
+ /// <param name="videoBitrate">The video bitrate to be used (kbps).</param>
+ /// <returns>The estimated file size (in MB) of the given job and video bitrate.</returns>
+ public double CalculateFileSize(EncodeJob job, int videoBitrate)
+ {
+ long totalBytes = 0;
+
+ EncodingProfile profile = job.EncodingProfile;
+ Title title = this.GetTitle(job.Title);
+
+ double lengthSeconds = HandBrakeUtils.GetJobLengthSeconds(job, title);
+ lengthSeconds += 1.5;
+
+ double outputFramerate;
+ if (profile.Framerate == 0)
+ {
+ outputFramerate = title.Framerate;
+ }
+ else
+ {
+ // Not sure what to do for VFR here hb_calc_bitrate never handled it...
+ // just use the peak for now.
+ outputFramerate = profile.Framerate;
+ }
+
+ long frames = (long)(lengthSeconds * outputFramerate);
+
+ totalBytes += (long)(lengthSeconds * videoBitrate * 125);
+ totalBytes += frames * HandBrakeUtils.ContainerOverheadPerFrame;
+
+ List<Tuple<AudioEncoding, int>> outputTrackList = this.GetOutputTracks(job, title);
+ totalBytes += HandBrakeUtils.GetAudioSize(job, lengthSeconds, title, outputTrackList);
+
+ return (double)totalBytes / 1024 / 1024;
+ }
+
+ /// <summary>
+ /// Starts an encode with the given job.
+ /// </summary>
+ /// <param name="jobToStart">The job to start.</param>
+ public void StartEncode(EncodeJob jobToStart)
+ {
+ this.StartEncode(jobToStart, false, 0, 0, 0);
+ }
+
+ /// <summary>
+ /// Starts an encode with the given job.
+ /// </summary>
+ /// <param name="job">The job to start.</param>
+ /// <param name="preview">True if this is a preview encode.</param>
+ /// <param name="previewNumber">The preview number to start the encode at (0-based).</param>
+ /// <param name="previewSeconds">The number of seconds in the preview.</param>
+ /// <param name="overallSelectedLengthSeconds">The currently selected encode length. Used in preview
+ /// for calculating bitrate when the target size would be wrong.</param>
+ public void StartEncode(EncodeJob job, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds)
+ {
+ this.currentJob = job;
+ hb_job_s nativeJob = InteropUtilities.ReadStructure<hb_job_s>(this.GetOriginalTitle(job.Title).job);
+ this.encodeAllocatedMemory = this.ApplyJob(ref nativeJob, job, preview, previewNumber, previewSeconds, overallSelectedLengthSeconds);
+
+ if (!preview && job.EncodingProfile.IncludeChapterMarkers)
+ {
+ Title title = this.GetTitle(job.Title);
+ int numChapters = title.Chapters.Count;
+
+ if (job.UseDefaultChapterNames)
+ {
+ for (int i = 0; i < numChapters; i++)
+ {
+ HBFunctions.hb_set_chapter_name(this.hbHandle, job.Title, i + 1, "Chapter " + (i + 1));
+ }
+ }
+ else
+ {
+ for (int i = 0; i < numChapters; i++)
+ {
+ HBFunctions.hb_set_chapter_name(this.hbHandle, job.Title, i + 1, job.CustomChapterNames[i]);
+ }
+ }
+ }
+
+ this.subtitleScan = false;
+ if (job.Subtitles.SourceSubtitles != null)
+ {
+ foreach (SourceSubtitle subtitle in job.Subtitles.SourceSubtitles)
+ {
+ if (subtitle.TrackNumber == 0)
+ {
+ this.subtitleScan = true;
+ break;
+ }
+ }
+ }
+
+ string x264Options = job.EncodingProfile.X264Options ?? string.Empty;
+ IntPtr originalX264Options = Marshal.StringToHGlobalAnsi(x264Options);
+ this.encodeAllocatedMemory.Add(originalX264Options);
+
+ if (this.subtitleScan)
+ {
+ // If we need to scan subtitles, enqueue a pre-processing job to do that.
+ nativeJob.pass = -1;
+ nativeJob.indepth_scan = 1;
+
+ nativeJob.advanced_opts = IntPtr.Zero;
+
+ HBFunctions.hb_add(this.hbHandle, ref nativeJob);
+ }
+
+ nativeJob.indepth_scan = 0;
+
+ if (job.EncodingProfile.TwoPass)
+ {
+ // First pass. Apply turbo options if needed.
+ nativeJob.pass = 1;
+ string firstPassAdvancedOptions = x264Options;
+ if (job.EncodingProfile.TurboFirstPass)
+ {
+ if (firstPassAdvancedOptions == string.Empty)
+ {
+ firstPassAdvancedOptions = TurboX264Opts;
+ }
+ else
+ {
+ firstPassAdvancedOptions += ":" + TurboX264Opts;
+ }
+ }
+
+ nativeJob.advanced_opts = Marshal.StringToHGlobalAnsi(firstPassAdvancedOptions);
+ this.encodeAllocatedMemory.Add(nativeJob.advanced_opts);
+
+ HBFunctions.hb_add(this.hbHandle, ref nativeJob);
+
+ // Second pass. Apply normal options.
+ nativeJob.pass = 2;
+ nativeJob.advanced_opts = originalX264Options;
+
+ HBFunctions.hb_add(this.hbHandle, ref nativeJob);
+ }
+ else
+ {
+ // One pass job.
+ nativeJob.pass = 0;
+ nativeJob.advanced_opts = originalX264Options;
+
+ HBFunctions.hb_add(this.hbHandle, ref nativeJob);
+ }
+
+ HBFunctions.hb_start(this.hbHandle);
+
+ this.encodePollTimer = new System.Timers.Timer();
+ this.encodePollTimer.Interval = EncodePollIntervalMs;
+
+ this.encodePollTimer.Elapsed += (o, e) =>
+ {
+ this.PollEncodeProgress();
+ };
+ this.encodePollTimer.Start();
+ }
+
+ /// <summary>
+ /// Pauses the current encode.
+ /// </summary>
+ public void PauseEncode()
+ {
+ HBFunctions.hb_pause(this.hbHandle);
+ }
+
+ /// <summary>
+ /// Resumes a paused encode.
+ /// </summary>
+ public void ResumeEncode()
+ {
+ HBFunctions.hb_resume(this.hbHandle);
+ }
+
+ /// <summary>
+ /// Stops the current encode.
+ /// </summary>
+ public void StopEncode()
+ {
+ HBFunctions.hb_stop(this.hbHandle);
+
+ // Also remove all jobs from the queue (in case we stopped a 2-pass encode)
+ var currentJobs = new List<IntPtr>();
+
+ int jobs = HBFunctions.hb_count(this.hbHandle);
+ for (int i = 0; i < jobs; i++)
+ {
+ currentJobs.Add(HBFunctions.hb_job(this.hbHandle, 0));
+ }
+
+ foreach (IntPtr job in currentJobs)
+ {
+ HBFunctions.hb_rem(this.hbHandle, job);
+ }
+ }
+
+ /// <summary>
+ /// Gets the final size for a given encode job.
+ /// </summary>
+ /// <param name="job">The encode job to use.</param>
+ /// <param name="width">The storage width.</param>
+ /// <param name="height">The storage height.</param>
+ /// <param name="parWidth">The pixel aspect X number.</param>
+ /// <param name="parHeight">The pixel aspect Y number.</param>
+ public void GetSize(EncodeJob job, out int width, out int height, out int parWidth, out int parHeight)
+ {
+ if (job.EncodingProfile.Anamorphic == Anamorphic.None)
+ {
+ Title title = this.GetTitle(job.Title);
+ Size storageDimensions = CalculateNonAnamorphicOutput(job.EncodingProfile, title);
+
+ width = storageDimensions.Width;
+ height = storageDimensions.Height;
+
+ parWidth = 1;
+ parHeight = 1;
+
+ return;
+ }
+
+ var nativeJob = InteropUtilities.ReadStructure<hb_job_s>(this.GetOriginalTitle(job.Title).job);
+ List<IntPtr> allocatedMemory = this.ApplyJob(ref nativeJob, job);
+
+ int refWidth = 0;
+ int refHeight = 0;
+ int refParWidth = 0;
+ int refParHeight = 0;
+ HBFunctions.hb_set_job(this.hbHandle, job.Title, ref nativeJob);
+ HBFunctions.hb_set_anamorphic_size_by_index(this.hbHandle, job.Title, ref refWidth, ref refHeight, ref refParWidth, ref refParHeight);
+ InteropUtilities.FreeMemory(allocatedMemory);
+
+ width = refWidth;
+ height = refHeight;
+ parWidth = refParWidth;
+ parHeight = refParHeight;
+ }
+
+ /// <summary>
+ /// Frees any resources associated with this object.
+ /// </summary>
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Call before app shutdown. Performs global cleanup.
+ /// </summary>
+ public static void DisposeGlobal()
+ {
+ HBFunctions.hb_global_close();
+ }
+
+ /// <summary>
+ /// Frees any resources associated with this object.
+ /// </summary>
+ /// <param name="disposing">True if managed objects as well as unmanaged should be disposed.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ // Free other state (managed objects).
+ }
+
+ // Free unmanaged objects.
+ IntPtr handlePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
+ Marshal.WriteIntPtr(handlePtr, this.hbHandle);
+ HBFunctions.hb_close(handlePtr);
+ Marshal.FreeHGlobal(handlePtr);
+ }
+
+ /// <summary>
+ /// Checks the status of the ongoing scan.
+ /// </summary>
+ private void PollScanProgress()
+ {
+ var state = new hb_state_s();
+ HBFunctions.hb_get_state(this.hbHandle, ref state);
+
+ if (state.state == NativeConstants.HB_STATE_SCANNING)
+ {
+ if (this.ScanProgress != null)
+ {
+ int currentTitle = state.param.scanning.title_cur;
+ int totalTitles = state.param.scanning.title_count;
+ this.ScanProgress(this, new ScanProgressEventArgs { CurrentTitle = currentTitle, Titles = totalTitles });
+ }
+ }
+ else if (state.state == NativeConstants.HB_STATE_SCANDONE)
+ {
+ this.titles = new List<Title>();
+
+ IntPtr listPtr = HBFunctions.hb_get_titles(this.hbHandle);
+ this.originalTitles = InteropUtilities.ConvertList<hb_title_s>(listPtr);
+
+ foreach (hb_title_s title in this.originalTitles)
+ {
+ var newTitle = this.ConvertTitle(title);
+ this.titles.Add(newTitle);
+ }
+
+ if (this.originalTitles.Count > 0)
+ {
+ var nativeJob = InteropUtilities.ReadStructure<hb_job_s>(this.originalTitles[0].job);
+ this.featureTitle = nativeJob.feature;
+ }
+ else
+ {
+ this.featureTitle = 0;
+ }
+
+ this.scanPollTimer.Stop();
+
+ if (this.ScanCompleted != null)
+ {
+ this.ScanCompleted(this, new EventArgs());
+ }
+ }
+ }
+
+ /// <summary>
+ /// Checks the status of the ongoing encode.
+ /// </summary>
+ private void PollEncodeProgress()
+ {
+ hb_state_s state = new hb_state_s();
+ HBFunctions.hb_get_state(this.hbHandle, ref state);
+
+ if (state.state == NativeConstants.HB_STATE_WORKING)
+ {
+ if (this.EncodeProgress != null)
+ {
+ int pass = 1;
+ int rawJobNumber = state.param.working.job_cur;
+
+ if (this.currentJob.EncodingProfile.TwoPass)
+ {
+ if (this.subtitleScan)
+ {
+ switch (rawJobNumber)
+ {
+ case 1:
+ pass = -1;
+ break;
+ case 2:
+ pass = 1;
+ break;
+ case 3:
+ pass = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (rawJobNumber)
+ {
+ case 1:
+ pass = 1;
+ break;
+ case 2:
+ pass = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (this.subtitleScan)
+ {
+ switch (rawJobNumber)
+ {
+ case 1:
+ pass = -1;
+ break;
+ case 2:
+ pass = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ pass = 1;
+ }
+ }
+
+ var progressEventArgs = new EncodeProgressEventArgs
+ {
+ FractionComplete = state.param.working.progress,
+ CurrentFrameRate = state.param.working.rate_cur,
+ AverageFrameRate = state.param.working.rate_avg,
+ EstimatedTimeLeft = new TimeSpan(state.param.working.hours, state.param.working.minutes, state.param.working.seconds),
+ Pass = pass
+ };
+
+ this.EncodeProgress(this, progressEventArgs);
+ }
+ }
+ else if (state.state == NativeConstants.HB_STATE_MUXING)
+ {
+ //System.Diagnostics.Debug.WriteLine("Muxing...");
+ }
+ else if (state.state == NativeConstants.HB_STATE_WORKDONE)
+ {
+ InteropUtilities.FreeMemory(this.encodeAllocatedMemory);
+ this.encodePollTimer.Stop();
+
+ if (this.EncodeCompleted != null)
+ {
+ this.EncodeCompleted(this, new EncodeCompletedEventArgs { Error = state.param.workdone.error > 0 });
+ }
+ }
+ }
+
+ /// <summary>
+ /// Applies the encoding job to the native memory structure and returns a list of memory
+ /// locations allocated during this.
+ /// </summary>
+ /// <param name="nativeJob">The native structure to apply to job info to.</param>
+ /// <param name="job">The job info to apply.</param>
+ /// <returns>The list of memory locations allocated for the job.</returns>
+ private List<IntPtr> ApplyJob(ref hb_job_s nativeJob, EncodeJob job)
+ {
+ return this.ApplyJob(ref nativeJob, job, false, 0, 0, 0);
+ }
+
+ /// <summary>
+ /// Applies the encoding job to the native memory structure and returns a list of memory
+ /// locations allocated during this.
+ /// </summary>
+ /// <param name="nativeJob">The native structure to apply to job info to.</param>
+ /// <param name="job">The job info to apply.</param>
+ /// <param name="preview">True if this is a preview encode.</param>
+ /// <param name="previewNumber">The preview number (0-based) to encode.</param>
+ /// <param name="previewSeconds">The number of seconds in the preview.</param>
+ /// <param name="overallSelectedLengthSeconds">The currently selected encode length. Used in preview
+ /// for calculating bitrate when the target size would be wrong.</param>
+ /// <returns>The list of memory locations allocated for the job.</returns>
+ private List<IntPtr> ApplyJob(ref hb_job_s nativeJob, EncodeJob job, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds)
+ {
+ var allocatedMemory = new List<IntPtr>();
+ Title title = this.GetTitle(job.Title);
+ hb_title_s originalTitle = this.GetOriginalTitle(job.Title);
+
+ EncodingProfile profile = job.EncodingProfile;
+
+ if (preview)
+ {
+ nativeJob.start_at_preview = previewNumber + 1;
+ nativeJob.seek_points = this.previewCount;
+
+ // There are 90,000 PTS per second.
+ nativeJob.pts_to_stop = previewSeconds * 90000;
+ }
+ else
+ {
+ switch (job.RangeType)
+ {
+ case VideoRangeType.Chapters:
+
+ if (job.ChapterStart > 0 && job.ChapterEnd > 0)
+ {
+ nativeJob.chapter_start = job.ChapterStart;
+ nativeJob.chapter_end = job.ChapterEnd;
+ }
+ else
+ {
+ nativeJob.chapter_start = 1;
+ nativeJob.chapter_end = title.Chapters.Count;
+ }
+
+ break;
+ case VideoRangeType.Seconds:
+ if (job.SecondsStart < 0 || job.SecondsEnd < 0 || job.SecondsStart >= job.SecondsEnd)
+ {
+ throw new ArgumentException("Seconds range " + job.SecondsStart + "-" + job.SecondsEnd + " is invalid.", "job");
+ }
+
+ // For some reason "pts_to_stop" actually means the number of pts to stop AFTER the start point.
+ nativeJob.pts_to_start = (int)(job.SecondsStart * 90000);
+ nativeJob.pts_to_stop = (int)((job.SecondsEnd - job.SecondsStart) * 90000);
+ break;
+ case VideoRangeType.Frames:
+ if (job.FramesStart < 0 || job.FramesEnd < 0 || job.FramesStart >= job.FramesEnd)
+ {
+ throw new ArgumentException("Frames range " + job.FramesStart + "-" + job.FramesEnd + " is invalid.", "job");
+ }
+
+ // "frame_to_stop" actually means the number of frames total to encode AFTER the start point.
+ nativeJob.frame_to_start = job.FramesStart;
+ nativeJob.frame_to_stop = job.FramesEnd - job.FramesStart;
+ break;
+ }
+ }
+
+ nativeJob.chapter_markers = profile.IncludeChapterMarkers ? 1 : 0;
+
+ Cropping crop;
+
+ if (profile.CustomCropping)
+ {
+ crop = profile.Cropping;
+ }
+ else
+ {
+ crop = title.AutoCropDimensions;
+ }
+
+ nativeJob.crop[0] = crop.Top;
+ nativeJob.crop[1] = crop.Bottom;
+ nativeJob.crop[2] = crop.Left;
+ nativeJob.crop[3] = crop.Right;
+
+ var filterList = new List<IntPtr>();
+ if (profile.Deinterlace != Deinterlace.Off)
+ {
+ nativeJob.deinterlace = 1;
+ string settings = null;
+
+ switch (profile.Deinterlace)
+ {
+ case Deinterlace.Fast:
+ settings = "-1";
+ break;
+ case Deinterlace.Slow:
+ settings = "2";
+ break;
+ case Deinterlace.Slower:
+ settings = "0";
+ break;
+ case Deinterlace.Custom:
+ settings = profile.CustomDeinterlace;
+ break;
+ default:
+ break;
+ }
+
+ this.AddFilter(filterList, NativeConstants.HB_FILTER_DEINTERLACE, settings, allocatedMemory);
+ }
+ else
+ {
+ nativeJob.deinterlace = 0;
+ }
+
+ if (profile.Detelecine != Detelecine.Off)
+ {
+ string settings = null;
+ if (profile.Detelecine == Detelecine.Custom)
+ {
+ settings = profile.CustomDetelecine;
+ }
+
+ this.AddFilter(filterList, NativeConstants.HB_FILTER_DETELECINE, settings, allocatedMemory);
+ }
+
+ if (profile.Decomb != Decomb.Off)
+ {
+ string settings = null;
+ if (profile.Decomb == Decomb.Custom)
+ {
+ settings = profile.CustomDecomb;
+ }
+
+ this.AddFilter(filterList, NativeConstants.HB_FILTER_DECOMB, settings, allocatedMemory);
+ }
+
+ if (profile.Deblock > 0)
+ {
+ this.AddFilter(filterList, NativeConstants.HB_FILTER_DEBLOCK, profile.Deblock.ToString(), allocatedMemory);
+ }
+
+ if (profile.Denoise != Denoise.Off)
+ {
+ string settings = null;
+ switch (profile.Denoise)
+ {
+ case Denoise.Weak:
+ settings = "2:1:2:3";
+ break;
+ case Denoise.Medium:
+ settings = "3:2:2:3";
+ break;
+ case Denoise.Strong:
+ settings = "7:7:5:5";
+ break;
+ case Denoise.Custom:
+ settings = profile.CustomDenoise;
+ break;
+ default:
+ break;
+ }
+
+ this.AddFilter(filterList, NativeConstants.HB_FILTER_DENOISE, settings, allocatedMemory);
+ }
+
+ NativeList filterListNative = InteropUtilities.CreateIntPtrList(filterList);
+ nativeJob.filters = filterListNative.ListPtr;
+ allocatedMemory.AddRange(filterListNative.AllocatedMemory);
+
+ int width = profile.Width;
+ int height = profile.Height;
+
+ int cropHorizontal = crop.Left + crop.Right;
+ int cropVertical = crop.Top + crop.Bottom;
+
+ if (width == 0)
+ {
+ width = title.Resolution.Width - cropHorizontal;
+ }
+
+ if (profile.MaxWidth > 0 && width > profile.MaxWidth)
+ {
+ width = profile.MaxWidth;
+ }
+
+ if (height == 0)
+ {
+ height = title.Resolution.Height - cropVertical;
+ }
+
+ if (profile.MaxHeight > 0 && height > profile.MaxHeight)
+ {
+ height = profile.MaxHeight;
+ }
+
+ nativeJob.grayscale = profile.Grayscale ? 1 : 0;
+
+ switch (profile.Anamorphic)
+ {
+ case Anamorphic.None:
+ nativeJob.anamorphic.mode = 0;
+
+ Size outputSize = CalculateNonAnamorphicOutput(profile, title);
+ width = outputSize.Width;
+ height = outputSize.Height;
+
+ nativeJob.anamorphic.keep_display_aspect = profile.KeepDisplayAspect ? 1 : 0;
+ break;
+ case Anamorphic.Strict:
+ nativeJob.anamorphic.mode = 1;
+ break;
+ case Anamorphic.Loose:
+ nativeJob.anamorphic.mode = 2;
+ break;
+ case Anamorphic.Custom:
+ nativeJob.anamorphic.mode = 3;
+
+ nativeJob.modulus = profile.Modulus;
+
+ if (profile.UseDisplayWidth)
+ {
+ if (profile.KeepDisplayAspect)
+ {
+ int cropWidth = title.Resolution.Width - cropHorizontal;
+ int cropHeight = title.Resolution.Height - cropVertical;
+
+ double displayAspect = ((double)(cropWidth * title.ParVal.Width)) / (cropHeight * title.ParVal.Height);
+ int displayWidth = profile.DisplayWidth;
+
+ if (profile.Height > 0)
+ {
+ displayWidth = (int)((double)profile.Height * displayAspect);
+ }
+ else if (displayWidth > 0)
+ {
+ height = (int)((double)displayWidth / displayAspect);
+ }
+ else
+ {
+ displayWidth = (int)((double)cropHeight * displayAspect);
+ }
+
+ nativeJob.anamorphic.dar_width = displayWidth;
+ nativeJob.anamorphic.dar_height = height;
+ nativeJob.anamorphic.keep_display_aspect = 1;
+ }
+
+ nativeJob.anamorphic.dar_width = profile.DisplayWidth;
+ nativeJob.anamorphic.dar_height = height;
+ nativeJob.anamorphic.keep_display_aspect = profile.KeepDisplayAspect ? 1 : 0;
+ }
+ else
+ {
+ nativeJob.anamorphic.par_width = profile.PixelAspectX;
+ nativeJob.anamorphic.par_height = profile.PixelAspectY;
+ nativeJob.anamorphic.keep_display_aspect = 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ nativeJob.width = width;
+ nativeJob.height = height;
+
+ nativeJob.maxWidth = profile.MaxWidth;
+ nativeJob.maxHeight = profile.MaxHeight;
+
+ switch (profile.VideoEncoder)
+ {
+ case VideoEncoder.X264:
+ nativeJob.vcodec = NativeConstants.HB_VCODEC_X264;
+ break;
+ case VideoEncoder.Theora:
+ nativeJob.vcodec = NativeConstants.HB_VCODEC_THEORA;
+ break;
+ case VideoEncoder.FFMpeg:
+ nativeJob.vcodec = NativeConstants.HB_VCODEC_FFMPEG;
+ break;
+ default:
+ break;
+ }
+
+ if (profile.Framerate == 0)
+ {
+ nativeJob.cfr = 0;
+ }
+ else
+ {
+ if (profile.PeakFramerate)
+ {
+ nativeJob.cfr = 2;
+ }
+ else
+ {
+ nativeJob.cfr = 1;
+ }
+
+ nativeJob.vrate = 27000000;
+ nativeJob.vrate_base = Converters.FramerateToVrate(profile.Framerate);
+ }
+
+ // vfr
+ // areBframes
+ // color_matrix
+ List<hb_audio_s> titleAudio = InteropUtilities.ConvertList<hb_audio_s>(originalTitle.list_audio);
+
+ var audioList = new List<hb_audio_s>();
+ int numTracks = 0;
+
+ List<Tuple<AudioEncoding, int>> outputTrackList = this.GetOutputTracks(job, title);
+
+ foreach (Tuple<AudioEncoding, int> outputTrack in outputTrackList)
+ {
+ audioList.Add(ConvertAudioBack(outputTrack.Item1, titleAudio[outputTrack.Item2 - 1], outputTrack.Item2, numTracks++, allocatedMemory));
+ }
+
+ NativeList nativeAudioList = InteropUtilities.ConvertListBack<hb_audio_s>(audioList);
+ nativeJob.list_audio = nativeAudioList.ListPtr;
+ allocatedMemory.AddRange(nativeAudioList.AllocatedMemory);
+
+ // Create a new empty list
+ int totalSubtitles = 0;
+ if (job.Subtitles != null)
+ {
+ if (job.Subtitles.SourceSubtitles != null)
+ {
+ totalSubtitles += job.Subtitles.SourceSubtitles.Count;
+ }
+
+ if (job.Subtitles.SrtSubtitles != null)
+ {
+ totalSubtitles += job.Subtitles.SrtSubtitles.Count;
+ }
+ }
+
+ NativeList nativeSubtitleList = InteropUtilities.CreateNativeList(totalSubtitles + 2);
+ nativeJob.list_subtitle = nativeSubtitleList.ListPtr;
+ allocatedMemory.AddRange(nativeSubtitleList.AllocatedMemory);
+
+ if (job.Subtitles != null)
+ {
+ if (job.Subtitles.SourceSubtitles != null && job.Subtitles.SourceSubtitles.Count > 0)
+ {
+ List<hb_subtitle_s> titleSubtitles = InteropUtilities.ConvertList<hb_subtitle_s>(originalTitle.list_subtitle);
+
+ foreach (SourceSubtitle sourceSubtitle in job.Subtitles.SourceSubtitles)
+ {
+ if (sourceSubtitle.TrackNumber == 0)
+ {
+ // Use subtitle search.
+ nativeJob.select_subtitle_config.force = sourceSubtitle.Forced ? 1 : 0;
+ nativeJob.select_subtitle_config.default_track = sourceSubtitle.Default ? 1 : 0;
+
+ if (!sourceSubtitle.BurnedIn)
+ {
+ nativeJob.select_subtitle_config.dest = hb_subtitle_config_s_subdest.PASSTHRUSUB;
+ }
+
+ nativeJob.indepth_scan = 1;
+ }
+ else
+ {
+ // Use specified subtitle.
+ hb_subtitle_s nativeSubtitle = titleSubtitles[sourceSubtitle.TrackNumber - 1];
+ var subtitleConfig = new hb_subtitle_config_s();
+
+ subtitleConfig.force = sourceSubtitle.Forced ? 1 : 0;
+ subtitleConfig.default_track = sourceSubtitle.Default ? 1 : 0;
+
+ bool supportsBurn = nativeSubtitle.source == hb_subtitle_s_subsource.VOBSUB || nativeSubtitle.source == hb_subtitle_s_subsource.SSASUB;
+ if (supportsBurn && sourceSubtitle.BurnedIn)
+ {
+ subtitleConfig.dest = hb_subtitle_config_s_subdest.RENDERSUB;
+ }
+ else
+ {
+ subtitleConfig.dest = hb_subtitle_config_s_subdest.PASSTHRUSUB;
+ }
+
+ int subtitleAddSucceded = HBFunctions.hb_subtitle_add(ref nativeJob, ref subtitleConfig, sourceSubtitle.TrackNumber - 1);
+ if (subtitleAddSucceded == 0)
+ {
+ System.Diagnostics.Debug.WriteLine("Subtitle add failed");
+ }
+ }
+ }
+ }
+
+ if (job.Subtitles.SrtSubtitles != null)
+ {
+ foreach (SrtSubtitle srtSubtitle in job.Subtitles.SrtSubtitles)
+ {
+ var subtitleConfig = new hb_subtitle_config_s();
+
+ subtitleConfig.src_codeset = srtSubtitle.CharacterCode;
+ subtitleConfig.src_filename = srtSubtitle.FileName;
+ subtitleConfig.offset = srtSubtitle.Offset;
+ //subtitleConfig.dest = hb_subtitle_config_s_subdest.PASSTHRUSUB;
+ subtitleConfig.default_track = srtSubtitle.Default ? 1 : 0;
+
+ int srtAddSucceded = HBFunctions.hb_srt_add(ref nativeJob, ref subtitleConfig, srtSubtitle.LanguageCode);
+ if (srtAddSucceded == 0)
+ {
+ System.Diagnostics.Debug.WriteLine("SRT add failed");
+ }
+ }
+ }
+ }
+
+ if (profile.OutputFormat == OutputFormat.Mp4)
+ {
+ nativeJob.mux = NativeConstants.HB_MUX_MP4;
+ }
+ else
+ {
+ nativeJob.mux = NativeConstants.HB_MUX_MKV;
+ }
+
+ nativeJob.file = job.OutputPath;
+
+ nativeJob.largeFileSize = profile.LargeFile ? 1 : 0;
+ nativeJob.mp4_optimize = profile.Optimize ? 1 : 0;
+ nativeJob.ipod_atom = profile.IPod5GSupport ? 1 : 0;
+
+ if (title.AngleCount > 1)
+ {
+ nativeJob.angle = job.Angle;
+ }
+
+ switch (profile.VideoEncodeRateType)
+ {
+ case VideoEncodeRateType.ConstantQuality:
+ nativeJob.vquality = (float)profile.Quality;
+ nativeJob.vbitrate = 0;
+ break;
+ case VideoEncodeRateType.AverageBitrate:
+ nativeJob.vquality = -1;
+ nativeJob.vbitrate = profile.VideoBitrate;
+ break;
+ case VideoEncodeRateType.TargetSize:
+ nativeJob.vquality = -1;
+ nativeJob.vbitrate = this.CalculateBitrate(job, profile.TargetSize, overallSelectedLengthSeconds);
+ break;
+ default:
+ break;
+ }
+
+ // frames_to_skip
+
+ return allocatedMemory;
+ }
+
+ /// <summary>
+ /// Gets a list of encodings and target track indices (1-based).
+ /// </summary>
+ /// <param name="job">The encode job</param>
+ /// <param name="title">The title the job is meant to encode.</param>
+ /// <returns>A list of encodings and target track indices (1-based).</returns>
+ private List<Tuple<AudioEncoding, int>> GetOutputTracks(EncodeJob job, Title title)
+ {
+ var list = new List<Tuple<AudioEncoding, int>>();
+
+ foreach (AudioEncoding encoding in job.EncodingProfile.AudioEncodings)
+ {
+ if (encoding.InputNumber == 0)
+ {
+ // Add this encoding for all chosen tracks
+ foreach (int chosenTrack in job.ChosenAudioTracks)
+ {
+ list.Add(new Tuple<AudioEncoding, int>(encoding, chosenTrack));
+ }
+ }
+ else if (encoding.InputNumber <= job.ChosenAudioTracks.Count)
+ {
+ // Add this encoding for the specified track, if it exists
+ int trackNumber = job.ChosenAudioTracks[encoding.InputNumber - 1];
+
+ // In normal cases we'll never have a chosen audio track that doesn't exist but when batch encoding
+ // we just choose the first audio track without checking if it exists.
+ if (trackNumber <= title.AudioTracks.Count)
+ {
+ list.Add(new Tuple<AudioEncoding, int>(encoding, trackNumber));
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /// <summary>
+ /// Adds a filter to the given filter list.
+ /// </summary>
+ /// <param name="filterList">The filter list to add to.</param>
+ /// <param name="filterType">The type of filter.</param>
+ /// <param name="settings">Settings for the filter.</param>
+ /// <param name="allocatedMemory">The list of allocated memory.</param>
+ private void AddFilter(List<IntPtr> filterList, int filterType, string settings, List<IntPtr> allocatedMemory)
+ {
+ IntPtr settingsNativeString = Marshal.StringToHGlobalAnsi(settings);
+ filterList.Add(HBFunctions.hb_get_filter_object(filterType, settingsNativeString));
+
+ allocatedMemory.Add(settingsNativeString);
+ }
+
+ /// <summary>
+ /// Gets the title, given the 1-based index.
+ /// </summary>
+ /// <param name="titleIndex">The index of the title (1-based).</param>
+ /// <returns>The requested Title.</returns>
+ private Title GetTitle(int titleIndex)
+ {
+ return this.Titles.SingleOrDefault(title => title.TitleNumber == titleIndex);
+ }
+
+ /// <summary>
+ /// Gets the native title object from the title index.
+ /// </summary>
+ /// <param name="titleIndex">The index of the title (1-based).</param>
+ /// <returns>Gets the native title object for the given index.</returns>
+ private hb_title_s GetOriginalTitle(int titleIndex)
+ {
+ List<hb_title_s> matchingTitles = this.originalTitles.Where(title => title.index == titleIndex).ToList();
+ if (matchingTitles.Count == 0)
+ {
+ throw new ArgumentException("Could not find specified title.");
+ }
+
+ if (matchingTitles.Count > 1)
+ {
+ throw new ArgumentException("Multiple titles matched.");
+ }
+
+ return matchingTitles[0];
+ }
+
+ /// <summary>
+ /// Applies an audio encoding to a native audio encoding base structure.
+ /// </summary>
+ /// <param name="encoding">The encoding to apply.</param>
+ /// <param name="baseStruct">The base native structure.</param>
+ /// <param name="track"></param>
+ /// <param name="outputTrack"></param>
+ /// <param name="allocatedMemory">The collection of allocated memory.</param>
+ /// <returns>The resulting native audio structure.</returns>
+ private hb_audio_s ConvertAudioBack(AudioEncoding encoding, hb_audio_s baseStruct, int track, int outputTrack, List<IntPtr> allocatedMemory)
+ {
+ hb_audio_s nativeAudio = baseStruct;
+
+ //nativeAudio.config.input.track = track;
+ nativeAudio.config.output.track = outputTrack;
+
+ if (encoding.Encoder == AudioEncoder.Passthrough)
+ {
+ // If we've been given a general "Passthrough" codec, see if it's valid for this input track.
+ if ((baseStruct.config.input.codec & NativeConstants.HB_ACODEC_PASS_MASK) > 0)
+ {
+ // We can do passthrough for this input.
+ nativeAudio.config.output.codec = nativeAudio.config.input.codec | NativeConstants.HB_ACODEC_PASS_FLAG;
+ }
+ else
+ {
+ // We can't do passthrough for this input. Set it to a DTS passthrough, which will cause the track to be dropped.
+ nativeAudio.config.output.codec = NativeConstants.HB_ACODEC_DCA_PASS;
+ }
+ }
+ else
+ {
+ nativeAudio.config.output.codec = Converters.AudioEncoderToNative(encoding.Encoder);
+ }
+
+ if (encoding.Encoder != AudioEncoder.Passthrough && encoding.Encoder != AudioEncoder.Ac3Passthrough && encoding.Encoder != AudioEncoder.DtsPassthrough)
+ {
+ nativeAudio.config.output.bitrate = encoding.Bitrate;
+ nativeAudio.config.output.dynamic_range_compression = 0.0;
+ nativeAudio.config.output.gain = encoding.Gain;
+
+ if (encoding.Mixdown == Mixdown.Auto)
+ {
+ nativeAudio.config.output.mixdown = HBFunctions.hb_get_default_mixdown(nativeAudio.config.output.codec, nativeAudio.config.input.channel_layout);
+ }
+ else
+ {
+ nativeAudio.config.output.mixdown = Converters.MixdownToNative(encoding.Mixdown);
+ }
+
+ if (encoding.SampleRateRaw == 0)
+ {
+ nativeAudio.config.output.samplerate = nativeAudio.config.input.samplerate;
+ }
+ else
+ {
+ nativeAudio.config.output.samplerate = encoding.SampleRateRaw;
+ }
+ }
+
+ if (!string.IsNullOrEmpty(encoding.Name))
+ {
+ IntPtr encodingNamePtr = Marshal.StringToHGlobalAnsi(encoding.Name);
+ nativeAudio.config.output.name = encodingNamePtr;
+ allocatedMemory.Add(encodingNamePtr);
+ }
+
+ nativeAudio.padding = new byte[MarshalingConstants.AudioPaddingBytes];
+
+ return nativeAudio;
+ }
+
+ /// <summary>
+ /// Converts a native title to a Title object.
+ /// </summary>
+ /// <param name="title">The native title structure.</param>
+ /// <returns>The managed Title object.</returns>
+ private Title ConvertTitle(hb_title_s title)
+ {
+ var newTitle = new Title
+ {
+ TitleNumber = title.index,
+ Resolution = new Size(title.width, title.height),
+ ParVal = new Size(title.pixel_aspect_width, title.pixel_aspect_height),
+ Duration = TimeSpan.FromSeconds(title.duration / 90000),
+ AutoCropDimensions = new Cropping
+ {
+ Top = title.crop[0],
+ Bottom = title.crop[1],
+ Left = title.crop[2],
+ Right = title.crop[3]
+ },
+ AspectRatio = title.aspect,
+ AngleCount = title.angle_count,
+ VideoCodecName = title.video_codec_name,
+ Framerate = ((double)title.rate) / title.rate_base
+ };
+
+ switch (title.type)
+ {
+ case hb_title_type_anon.HB_STREAM_TYPE:
+ newTitle.InputType = InputType.Stream;
+ break;
+ case hb_title_type_anon.HB_DVD_TYPE:
+ newTitle.InputType = InputType.Dvd;
+ break;
+ case hb_title_type_anon.HB_BD_TYPE:
+ newTitle.InputType = InputType.Bluray;
+ break;
+ }
+
+ int currentSubtitleTrack = 1;
+ List<hb_subtitle_s> subtitleList = InteropUtilities.ConvertList<hb_subtitle_s>(title.list_subtitle);
+ foreach (hb_subtitle_s subtitle in subtitleList)
+ {
+ var newSubtitle = new Subtitle
+ {
+ TrackNumber = currentSubtitleTrack,
+ Language = subtitle.lang,
+ LanguageCode = subtitle.iso639_2
+ };
+
+ if (subtitle.format == hb_subtitle_s_subtype.PICTURESUB)
+ {
+ newSubtitle.SubtitleType = SubtitleType.Picture;
+ }
+ else if (subtitle.format == hb_subtitle_s_subtype.TEXTSUB)
+ {
+ newSubtitle.SubtitleType = SubtitleType.Text;
+ }
+
+ switch (subtitle.source)
+ {
+ case hb_subtitle_s_subsource.CC608SUB:
+ newSubtitle.SubtitleSource = SubtitleSource.CC608;
+ break;
+ case hb_subtitle_s_subsource.CC708SUB:
+ newSubtitle.SubtitleSource = SubtitleSource.CC708;
+ break;
+ case hb_subtitle_s_subsource.SRTSUB:
+ newSubtitle.SubtitleSource = SubtitleSource.SRT;
+ break;
+ case hb_subtitle_s_subsource.SSASUB:
+ newSubtitle.SubtitleSource = SubtitleSource.SSA;
+ break;
+ case hb_subtitle_s_subsource.TX3GSUB:
+ newSubtitle.SubtitleSource = SubtitleSource.TX3G;
+ break;
+ case hb_subtitle_s_subsource.UTF8SUB:
+ newSubtitle.SubtitleSource = SubtitleSource.UTF8;
+ break;
+ case hb_subtitle_s_subsource.VOBSUB:
+ newSubtitle.SubtitleSource = SubtitleSource.VobSub;
+ break;
+ default:
+ break;
+ }
+
+ newTitle.Subtitles.Add(newSubtitle);
+
+ currentSubtitleTrack++;
+ }
+
+ int currentAudioTrack = 1;
+ List<hb_audio_s> audioList = InteropUtilities.ConvertList<hb_audio_s>(title.list_audio);
+ foreach (hb_audio_s audio in audioList)
+ {
+ var newAudio = new AudioTrack
+ {
+ TrackNumber = currentAudioTrack,
+ Codec = Converters.NativeToAudioCodec(audio.config.input.codec),
+ Language = audio.config.lang.simple,
+ LanguageCode = audio.config.lang.iso639_2,
+ Description = audio.config.lang.description,
+ ChannelLayout = audio.config.input.channel_layout,
+ SampleRate = audio.config.input.samplerate,
+ Bitrate = audio.config.input.bitrate
+ };
+
+ newTitle.AudioTracks.Add(newAudio);
+
+ currentAudioTrack++;
+ }
+
+ List<hb_chapter_s> chapterList = InteropUtilities.ConvertList<hb_chapter_s>(title.list_chapter);
+ foreach (hb_chapter_s chapter in chapterList)
+ {
+ var newChapter = new Chapter
+ {
+ ChapterNumber = chapter.index,
+ Duration = TimeSpan.FromSeconds(((double)chapter.duration) / 90000)
+ };
+
+ newTitle.Chapters.Add(newChapter);
+ }
+
+ return newTitle;
+ }
+
+ /// <summary>
+ /// Calculates the output size for a non-anamorphic job.
+ /// </summary>
+ /// <param name="profile">The encoding profile for the job.</param>
+ /// <param name="title">The title being encoded.</param>
+ /// <returns>The dimensions of the final encode.</returns>
+ private static Size CalculateNonAnamorphicOutput(EncodingProfile profile, Title title)
+ {
+ int sourceWidth = title.Resolution.Width;
+ int sourceHeight = title.Resolution.Height;
+
+ int width = profile.Width;
+ int height = profile.Height;
+
+ Cropping crop;
+ if (profile.CustomCropping)
+ {
+ crop = profile.Cropping;
+ }
+ else
+ {
+ crop = title.AutoCropDimensions;
+ }
+
+ sourceWidth -= crop.Left;
+ sourceWidth -= crop.Right;
+
+ sourceHeight -= crop.Top;
+ sourceHeight -= crop.Bottom;
+
+ double croppedAspectRatio = ((double)sourceWidth * title.ParVal.Width) / (sourceHeight * title.ParVal.Height);
+
+ if (width == 0)
+ {
+ width = sourceWidth;
+ }
+
+ if (profile.MaxWidth > 0 && width > profile.MaxWidth)
+ {
+ width = profile.MaxWidth;
+ }
+
+ if (height == 0)
+ {
+ height = sourceHeight;
+ }
+
+ if (profile.MaxHeight > 0 && height > profile.MaxHeight)
+ {
+ height = profile.MaxHeight;
+ }
+
+ if (profile.KeepDisplayAspect)
+ {
+ if (profile.Width == 0 && profile.Height == 0 || profile.Width == 0)
+ {
+ width = (int)((double)height * croppedAspectRatio);
+ if (profile.MaxWidth > 0 && width > profile.MaxWidth)
+ {
+ width = profile.MaxWidth;
+ height = (int)((double)width / croppedAspectRatio);
+ height = GetNearestValue(height, PictureAutoSizeModulus);
+ }
+
+ width = GetNearestValue(width, PictureAutoSizeModulus);
+ }
+ else if (profile.Height == 0)
+ {
+ height = (int)((double)width / croppedAspectRatio);
+ if (profile.MaxHeight > 0 && height > profile.MaxHeight)
+ {
+ height = profile.MaxHeight;
+ width = (int)((double)height * croppedAspectRatio);
+ width = GetNearestValue(width, PictureAutoSizeModulus);
+ }
+
+ height = GetNearestValue(height, PictureAutoSizeModulus);
+ }
+ }
+
+ return new Size(width, height);
+ }
+
+ /// <summary>
+ /// Gets the closest value to the given number divisible by the given modulus.
+ /// </summary>
+ /// <param name="number">The number to approximate.</param>
+ /// <param name="modulus">The modulus.</param>
+ /// <returns>The closest value to the given number divisible by the given modulus.</returns>
+ private static int GetNearestValue(int number, int modulus)
+ {
+ return modulus * ((number + modulus / 2) / modulus);
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj
new file mode 100644
index 000000000..24668cadd
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{F0A61F62-2C3B-4A87-AFF4-0C4256253DA1}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>HandBrake.Interop</RootNamespace>
+ <AssemblyName>HandBrakeInterop</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x64\Debug\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;X64</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x64</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Debug\HandBrakeInterop.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ <CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ <OutputPath>bin\x64\Release\</OutputPath>
+ <DefineConstants>TRACE;X64</DefineConstants>
+ <Optimize>true</Optimize>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>x64</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Release\HandBrakeInterop.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x86\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Debug\HandBrakeInterop.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+ <OutputPath>bin\x86\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <Optimize>true</Optimize>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Release\HandBrakeInterop.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ <CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="PresentationCore">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Xaml" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Converters.cs" />
+ <Compile Include="EncodeCompletedEventArgs.cs" />
+ <Compile Include="EncodeProgressEventArgs.cs" />
+ <Compile Include="HandBrakeUtils.cs" />
+ <Compile Include="HandBrakeInstance.cs" />
+ <Compile Include="HbLib\HBFunctions.cs" />
+ <Compile Include="HbLib\hb_audio.cs" />
+ <Compile Include="HbLib\hb_chapter_s.cs" />
+ <Compile Include="HbLib\hb_handle_s.cs" />
+ <Compile Include="HbLib\hb_subtitle.cs" />
+ <Compile Include="HbLib\Misc.cs" />
+ <Compile Include="HbLib\hb_job_s.cs" />
+ <Compile Include="HbLib\hb_title_s.cs" />
+ <Compile Include="HbLib\NativeConstants.cs" />
+ <Compile Include="InteropUtilities.cs" />
+ <Compile Include="Language.cs" />
+ <Compile Include="LanguageCodes.cs" />
+ <Compile Include="MarshalingConstants.cs" />
+ <Compile Include="MessageLoggedEventArgs.cs" />
+ <Compile Include="Model\Cropping.cs" />
+ <Compile Include="Model\EncodeJob.cs" />
+ <Compile Include="Model\Encoding\Anamorphic.cs" />
+ <Compile Include="Model\Encoding\AudioEncoder.cs" />
+ <Compile Include="Model\Encoding\AudioEncoding.cs" />
+ <Compile Include="Model\Encoding\Decomb.cs" />
+ <Compile Include="Model\Encoding\Deinterlace.cs" />
+ <Compile Include="Model\Encoding\Denoise.cs" />
+ <Compile Include="Model\Encoding\Detelecine.cs" />
+ <Compile Include="Model\Encoding\EncodingProfile.cs" />
+ <Compile Include="Model\Encoding\Mixdown.cs" />
+ <Compile Include="Model\Encoding\OutputExtension.cs" />
+ <Compile Include="Model\Encoding\OutputFormat.cs" />
+ <Compile Include="Model\Encoding\VideoEncoder.cs" />
+ <Compile Include="Model\Encoding\VideoEncodeRateType.cs" />
+ <Compile Include="Model\Limits.cs" />
+ <Compile Include="Model\Size.cs" />
+ <Compile Include="Model\SourceSubtitle.cs" />
+ <Compile Include="Model\SourceType.cs" />
+ <Compile Include="Model\SrtSubtitle.cs" />
+ <Compile Include="Model\Subtitles.cs" />
+ <Compile Include="Model\VideoRangeType.cs" />
+ <Compile Include="NativeList.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ScanProgressEventArgs.cs" />
+ <Compile Include="SourceData\AudioCodec.cs" />
+ <Compile Include="SourceData\AudioTrack.cs" />
+ <Compile Include="SourceData\Chapter.cs" />
+ <Compile Include="SourceData\InputType.cs" />
+ <Compile Include="SourceData\Subtitle.cs" />
+ <Compile Include="SourceData\SubtitleSource.cs" />
+ <Compile Include="SourceData\SubtitleType.cs" />
+ <Compile Include="SourceData\Title.cs" />
+ <Compile Include="Utilities.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>-->
+ <Target Name="AfterBuild">
+ <Copy SourceFiles="..\..\Lib\$(Platform)\hb.dll" DestinationFolder="$(OutDir)" />
+ </Target>
+</Project> \ No newline at end of file
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs
new file mode 100644
index 000000000..89134b4ab
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs
@@ -0,0 +1,254 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HandBrake.SourceData;
+
+namespace HandBrake.Interop
+{
+ public static class HandBrakeUtils
+ {
+ /// <summary>
+ /// Estimated overhead in bytes for each frame in output container.
+ /// </summary>
+ internal const int ContainerOverheadPerFrame = 6;
+
+ /// <summary>
+ /// The callback for log messages from HandBrake.
+ /// </summary>
+ private static LoggingCallback loggingCallback;
+
+ /// <summary>
+ /// The callback for error messages from HandBrake.
+ /// </summary>
+ private static LoggingCallback errorCallback;
+
+ /// <summary>
+ /// Fires when HandBrake has logged a message.
+ /// </summary>
+ public static event EventHandler<MessageLoggedEventArgs> MessageLogged;
+
+ /// <summary>
+ /// Fires when HandBrake has logged an error.
+ /// </summary>
+ public static event EventHandler<MessageLoggedEventArgs> ErrorLogged;
+
+ public static void RegisterLogger()
+ {
+ // Register the logger if we have not already
+ if (loggingCallback == null)
+ {
+ // Keep the callback as a member to prevent it from being garbage collected.
+ loggingCallback = new LoggingCallback(LoggingHandler);
+ errorCallback = new LoggingCallback(ErrorHandler);
+ HBFunctions.hb_register_logger(loggingCallback);
+ HBFunctions.hb_register_error_handler(errorCallback);
+ }
+ }
+
+ /// <summary>
+ /// Handles log messages from HandBrake.
+ /// </summary>
+ /// <param name="message">The log message (including newline).</param>
+ public static void LoggingHandler(string message)
+ {
+ if (!string.IsNullOrEmpty(message))
+ {
+ string[] messageParts = message.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
+
+ if (messageParts.Length > 0)
+ {
+ if (MessageLogged != null)
+ {
+ MessageLogged(null, new MessageLoggedEventArgs { Message = messageParts[0] });
+ }
+
+ System.Diagnostics.Debug.WriteLine(messageParts[0]);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Handles errors from HandBrake.
+ /// </summary>
+ /// <param name="message">The error message.</param>
+ public static void ErrorHandler(string message)
+ {
+ if (!string.IsNullOrEmpty(message))
+ {
+ // This error happens in normal operations. Log it as a message.
+ if (message == "dvd: ifoOpen failed")
+ {
+ if (MessageLogged != null)
+ {
+ MessageLogged(null, new MessageLoggedEventArgs { Message = message });
+ }
+
+ return;
+ }
+
+ if (ErrorLogged != null)
+ {
+ ErrorLogged(null, new MessageLoggedEventArgs { Message = message });
+ }
+
+ System.Diagnostics.Debug.WriteLine("ERROR: " + message);
+ }
+ }
+
+ /// <summary>
+ /// Gets the default mixdown for the given audio encoder and channel layout.
+ /// </summary>
+ /// <param name="encoder">The output codec to be used.</param>
+ /// <param name="layout">The input channel layout.</param>
+ /// <returns>The default mixdown for the given codec and channel layout.</returns>
+ public static Mixdown GetDefaultMixdown(AudioEncoder encoder, int layout)
+ {
+ int defaultMixdown = HBFunctions.hb_get_default_mixdown(Converters.AudioEncoderToNative(encoder), layout);
+ return Converters.NativeToMixdown(defaultMixdown);
+ }
+
+ /// <summary>
+ /// Gets the bitrate limits for the given audio codec, sample rate and mixdown.
+ /// </summary>
+ /// <param name="encoder">The audio encoder used.</param>
+ /// <param name="sampleRate">The sample rate used (Hz).</param>
+ /// <param name="mixdown">The mixdown used.</param>
+ /// <returns>Limits on the audio bitrate for the given settings.</returns>
+ public static Limits GetBitrateLimits(AudioEncoder encoder, int sampleRate, Mixdown mixdown)
+ {
+ if (mixdown == Mixdown.Auto)
+ {
+ throw new ArgumentException("Mixdown cannot be Auto.");
+ }
+
+ int low = 0;
+ int high = 0;
+
+ HBFunctions.hb_get_audio_bitrate_limits(Converters.AudioEncoderToNative(encoder), sampleRate, Converters.MixdownToNative(mixdown), ref low, ref high);
+
+ return new Limits { Low = low, High = high };
+ }
+
+ /// <summary>
+ /// Sanitizes a mixdown given the output codec and input channel layout.
+ /// </summary>
+ /// <param name="mixdown">The desired mixdown.</param>
+ /// <param name="encoder">The output encoder to be used.</param>
+ /// <param name="layout">The input channel layout.</param>
+ /// <returns>A sanitized mixdown value.</returns>
+ public static Mixdown SanitizeMixdown(Mixdown mixdown, AudioEncoder encoder, int layout)
+ {
+ int sanitizedMixdown = HBFunctions.hb_get_best_mixdown(Converters.AudioEncoderToNative(encoder), layout, Converters.MixdownToNative(mixdown));
+ return Converters.NativeToMixdown(sanitizedMixdown);
+ }
+
+ /// <summary>
+ /// Sanitizes an audio bitrate given the output codec, sample rate and mixdown.
+ /// </summary>
+ /// <param name="audioBitrate">The desired audio bitrate.</param>
+ /// <param name="encoder">The output encoder to be used.</param>
+ /// <param name="sampleRate">The output sample rate to be used.</param>
+ /// <param name="mixdown">The mixdown to be used.</param>
+ /// <returns>A sanitized audio bitrate.</returns>
+ public static int SanitizeAudioBitrate(int audioBitrate, AudioEncoder encoder, int sampleRate, Mixdown mixdown)
+ {
+ return HBFunctions.hb_get_best_audio_bitrate(Converters.AudioEncoderToNative(encoder), audioBitrate, sampleRate, Converters.MixdownToNative(mixdown));
+ }
+
+ /// <summary>
+ /// Gets the total number of seconds on the given encode job.
+ /// </summary>
+ /// <param name="job">The encode job to query.</param>
+ /// <param name="title">The title being encoded.</param>
+ /// <returns>The total number of seconds of video to encode.</returns>
+ internal static double GetJobLengthSeconds(EncodeJob job, Title title)
+ {
+ switch (job.RangeType)
+ {
+ case VideoRangeType.Chapters:
+ TimeSpan duration = TimeSpan.Zero;
+ for (int i = job.ChapterStart; i <= job.ChapterEnd; i++)
+ {
+ duration += title.Chapters[i - 1].Duration;
+ }
+
+ return duration.TotalSeconds;
+ case VideoRangeType.Seconds:
+ return job.SecondsEnd - job.SecondsStart;
+ case VideoRangeType.Frames:
+ return (job.FramesEnd - job.FramesStart) / title.Framerate;
+ }
+
+ return 0;
+ }
+
+ /// <summary>
+ /// Gets the number of audio samples used per frame for the given audio encoder.
+ /// </summary>
+ /// <param name="encoder">The encoder to query.</param>
+ /// <returns>The number of audio samples used per frame for the given
+ /// audio encoder.</returns>
+ internal static int GetAudioSamplesPerFrame(AudioEncoder encoder)
+ {
+ switch (encoder)
+ {
+ case AudioEncoder.Faac:
+ case AudioEncoder.Vorbis:
+ return 1024;
+ case AudioEncoder.Lame:
+ return 1152;
+ case AudioEncoder.Ac3:
+ case AudioEncoder.Passthrough:
+ case AudioEncoder.Ac3Passthrough:
+ case AudioEncoder.DtsPassthrough:
+ return 1536;
+ }
+
+ System.Diagnostics.Debug.Assert(true, "Audio encoder unrecognized.");
+ return 0;
+ }
+
+ /// <summary>
+ /// Gets the size in bytes for the audio with the given parameters.
+ /// </summary>
+ /// <param name="job">The encode job.</param>
+ /// <param name="lengthSeconds">The length of the encode in seconds.</param>
+ /// <param name="title">The title to encode.</param>
+ /// <param name="outputTrackList">The list of tracks to encode.</param>
+ /// <returns>The size in bytes for the audio with the given parameters.</returns>
+ internal static long GetAudioSize(EncodeJob job, double lengthSeconds, Title title, List<Tuple<AudioEncoding, int>> outputTrackList)
+ {
+ long audioBytes = 0;
+
+ foreach (Tuple<AudioEncoding, int> outputTrack in outputTrackList)
+ {
+ AudioEncoding encoding = outputTrack.Item1;
+ AudioTrack track = title.AudioTracks[outputTrack.Item2 - 1];
+
+ int samplesPerFrame = HandBrakeUtils.GetAudioSamplesPerFrame(encoding.Encoder);
+ int audioBitrate;
+
+ if (encoding.Encoder == AudioEncoder.Passthrough ||
+ encoding.Encoder == AudioEncoder.Ac3Passthrough ||
+ encoding.Encoder == AudioEncoder.DtsPassthrough)
+ {
+ // Input bitrate is in bits/second.
+ audioBitrate = track.Bitrate / 8;
+ }
+ else
+ {
+ // Output bitrate is in kbps.
+ audioBitrate = encoding.Bitrate * 1000 / 8;
+ }
+
+ audioBytes += (long)(lengthSeconds * audioBitrate);
+
+ // Audio overhead
+ audioBytes += encoding.SampleRateRaw * ContainerOverheadPerFrame / samplesPerFrame;
+ }
+
+ return audioBytes;
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs
new file mode 100644
index 000000000..fa5a321ca
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public static class HBFunctions
+ {
+ [DllImport("hb.dll", EntryPoint = "hb_register_logger", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_register_logger(LoggingCallback callback);
+
+ [DllImport("hb.dll", EntryPoint = "hb_register_error_handler", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_register_error_handler(LoggingCallback callback);
+
+ /// Return Type: hb_handle_t*
+ ///verbose: int
+ ///update_check: int
+ [DllImport("hb.dll", EntryPoint = "hb_init", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr hb_init(int verbose, int update_check);
+
+
+ /// Return Type: hb_handle_t*
+ ///verbose: int
+ ///update_check: int
+ [DllImport("hb.dll", EntryPoint = "hb_init_dl", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr hb_init_dl(int verbose, int update_check);
+
+
+ /// Return Type: char*
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_get_version", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr hb_get_version(ref hb_handle_s param0);
+
+
+ /// Return Type: int
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_get_build", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_get_build(ref hb_handle_s param0);
+
+
+ /// Return Type: int
+ ///h: hb_handle_t*
+ ///version: char**
+ [DllImport("hb.dll", EntryPoint = "hb_check_update", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_check_update(ref hb_handle_s h, ref IntPtr version);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ ///param1: int
+ [DllImport("hb.dll", EntryPoint = "hb_set_cpu_count", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_set_cpu_count(ref hb_handle_s param0, int param1);
+
+
+ /// Return Type: char*
+ ///path: char*
+ [DllImport("hb.dll", EntryPoint = "hb_dvd_name", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr hb_dvd_name(IntPtr path);
+
+
+ /// Return Type: void
+ ///enable: int
+ [DllImport("hb.dll", EntryPoint = "hb_dvd_set_dvdnav", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_dvd_set_dvdnav(int enable);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ ///path: char*
+ ///title_index: int
+ ///preview_count: int
+ ///store_previews: int
+ [DllImport("hb.dll", EntryPoint = "hb_scan", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_scan(IntPtr hbHandle, [In] [MarshalAs(UnmanagedType.LPStr)] string path, int title_index, int preview_count, int store_previews, ulong min_duration);
+
+ [DllImport("hb.dll", EntryPoint = "hb_scan_stop", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_scan_stop(IntPtr hbHandle);
+
+ /// Return Type: hb_list_t*
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_get_titles", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr hb_get_titles(IntPtr hbHandle);
+
+
+ /// Return Type: int
+ ///buf: hb_buffer_t*
+ ///width: int
+ ///height: int
+ ///color_equal: int
+ ///color_diff: int
+ ///threshold: int
+ ///prog_equal: int
+ ///prog_diff: int
+ ///prog_threshold: int
+ [DllImport("hb.dll", EntryPoint = "hb_detect_comb", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_detect_comb(ref hb_buffer_s buf, int width, int height, int color_equal, int color_diff, int threshold, int prog_equal, int prog_diff, int prog_threshold);
+
+ [DllImport("hb.dll", EntryPoint = "hb_get_preview_by_index", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_get_preview_by_index(IntPtr hbHandle, int title_index, int picture, IntPtr buffer);
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ ///param1: hb_title_t*
+ ///param2: int
+ ///param3: uint8_t*
+ [DllImport("hb.dll", EntryPoint = "hb_get_preview", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_get_preview(IntPtr hbHandle, ref hb_title_s title, int preview, IntPtr buffer);
+
+
+ /// Return Type: void
+ ///param0: hb_job_t*
+ ///ratio: double
+ ///pixels: int
+ [DllImport("hb.dll", EntryPoint = "hb_set_size", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_set_size(ref hb_job_s param0, double ratio, int pixels);
+
+ [DllImport("hb.dll", EntryPoint = "hb_set_anamorphic_size_by_index", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_set_anamorphic_size_by_index(IntPtr hbHandle, int title_index, ref int output_width, ref int output_height, ref int output_par_width, ref int output_par_height);
+
+ /// Return Type: void
+ ///param0: hb_job_t*
+ ///output_width: int*
+ ///output_height: int*
+ ///output_par_width: int*
+ ///output_par_height: int*
+ [DllImport("hb.dll", EntryPoint = "hb_set_anamorphic_size", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_set_anamorphic_size(ref hb_job_s job, ref int output_width, ref int output_height, ref int output_par_width, ref int output_par_height);
+
+
+ /// Return Type: int
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_count", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_count(IntPtr hbHandle);
+
+
+ /// Return Type: hb_job_t*
+ ///param0: hb_handle_t*
+ ///param1: int
+ [DllImport("hb.dll", EntryPoint = "hb_job", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr hb_job(IntPtr hbHandle, int jobIndex);
+
+ [DllImport("hb.dll", EntryPoint = "hb_set_chapter_name", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_set_chapter_name(IntPtr hbHandle, int title_index, int chapter_index, [In] [MarshalAs(UnmanagedType.LPStr)] string chapter_name);
+
+ [DllImport("hb.dll", EntryPoint = "hb_set_job", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_set_job(IntPtr hbHandle, int title_index, ref hb_job_s job);
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ ///param1: hb_job_t*
+ [DllImport("hb.dll", EntryPoint = "hb_add", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_add(IntPtr hbHandle, ref hb_job_s job);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ ///param1: hb_job_t*
+ [DllImport("hb.dll", EntryPoint = "hb_rem", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_rem(IntPtr hbHandle, IntPtr job);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_start", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_start(IntPtr hbHandle);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_pause", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_pause(IntPtr hbHandle);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_resume", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_resume(IntPtr hbHandle);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_stop", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_stop(IntPtr hbHandle);
+
+ [DllImport("hb.dll", EntryPoint = "hb_get_filter_object", CallingConvention = CallingConvention.Cdecl)]
+ //public static extern IntPtr hb_get_filter_object(int filter_id, [In] [MarshalAs(UnmanagedType.LPStr)] string settings);
+ public static extern IntPtr hb_get_filter_object(int filter_id, IntPtr settings);
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ ///param1: hb_state_t*
+ [DllImport("hb.dll", EntryPoint = "hb_get_state", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_get_state(IntPtr hbHandle, ref hb_state_s state);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t*
+ ///param1: hb_state_t*
+ [DllImport("hb.dll", EntryPoint = "hb_get_state2", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_get_state2(ref hb_handle_s param0, ref hb_state_s param1);
+
+
+ /// Return Type: int
+ ///param0: hb_handle_t*
+ [DllImport("hb.dll", EntryPoint = "hb_get_scancount", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_get_scancount(ref hb_handle_s param0);
+
+
+ /// Return Type: void
+ ///param0: hb_handle_t**
+ [DllImport("hb.dll", EntryPoint = "hb_close", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_close(IntPtr hbHandle);
+
+ [DllImport("hb.dll", EntryPoint = "hb_global_close", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void hb_global_close();
+
+ [DllImport("hb.dll", EntryPoint = "hb_subtitle_add", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_subtitle_add(ref hb_job_s job, ref hb_subtitle_config_s subtitleConfig, int track);
+
+ [DllImport("hb.dll", EntryPoint = "hb_srt_add", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_srt_add(ref hb_job_s job, ref hb_subtitle_config_s subtitleConfig, string lang);
+
+ [DllImport("hb.dll", EntryPoint = "hb_get_default_mixdown", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_get_default_mixdown(uint codec, int layout);
+
+ [DllImport("hb.dll", EntryPoint = "hb_get_best_mixdown", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_get_best_mixdown(uint codec, int layout, int mixdown);
+
+ [DllImport("hb.dll", EntryPoint = "hb_get_best_audio_bitrate", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_get_best_audio_bitrate(uint codec, int bitrate, int samplerate, int mixdown);
+
+ [DllImport("hb.dll", EntryPoint = "hb_get_audio_bitrate_limits", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_get_audio_bitrate_limits(uint codec, int samplerate, int mixdown, ref int low, ref int high);
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs
new file mode 100644
index 000000000..7d742f6c9
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs
@@ -0,0 +1,415 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace HandBrake.Interop
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_anamorphic_substruct
+ {
+ /// int
+ public int mode;
+
+ /// int
+ public int itu_par;
+
+ /// int
+ public int par_width;
+
+ /// int
+ public int par_height;
+
+ /// int
+ public int dar_width;
+
+ /// int
+ public int dar_height;
+
+ /// int
+ public int keep_display_aspect;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_list_s
+ {
+ /// void**
+ public IntPtr items;
+
+ /// int
+ public int items_alloc;
+
+ /// int
+ public int items_count;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_rate_s
+ {
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string @string;
+
+ /// int
+ public int rate;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct hb_metadata_s
+ {
+ /// char[255]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
+ public string name;
+
+ /// char[255]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
+ public string artist;
+
+ /// char[255]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
+ public string composer;
+
+ /// char[255]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
+ public string release_date;
+
+ /// char[1024]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string comment;
+
+ /// char[255]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
+ public string album;
+
+ /// char[255]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
+ public string genre;
+
+ /// uint32_t->unsigned int
+ public uint coverart_size;
+
+ /// uint8_t*
+ public IntPtr coverart;
+ }
+
+ public enum hb_title_type_anon
+ {
+ HB_DVD_TYPE,
+
+ HB_BD_TYPE,
+
+ HB_STREAM_TYPE,
+
+ HB_FF_STREAM_TYPE,
+ }
+
+ public enum Anonymous_618ebeca_0ad9_4a71_9a49_18e50ac2e9db
+ {
+ /// HB_MPEG2_PS_DEMUXER -> 0
+ HB_MPEG2_PS_DEMUXER = 0,
+
+ HB_MPEG2_TS_DEMUXER,
+
+ HB_NULL_DEMUXER,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_state_scanning_anon
+ {
+ /// int
+ public int title_cur;
+
+ /// int
+ public int title_count;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_state_working_anon
+ {
+ /// float
+ public float progress;
+
+ /// int
+ public int job_cur;
+
+ /// int
+ public int job_count;
+
+ /// float
+ public float rate_cur;
+
+ /// float
+ public float rate_avg;
+
+ /// int
+ public int hours;
+
+ /// int
+ public int minutes;
+
+ /// int
+ public int seconds;
+
+ /// int
+ public int sequence_id;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_state_workdone_anon
+ {
+ /// int
+ public int error;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_state_muxing_anon
+ {
+ /// float
+ public float progress;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct hb_state_param_u
+ {
+ [FieldOffset(0)]
+ public hb_state_scanning_anon scanning;
+
+ [FieldOffset(0)]
+ public hb_state_working_anon working;
+
+ [FieldOffset(0)]
+ public hb_state_workdone_anon workdone;
+
+ [FieldOffset(0)]
+ public hb_state_muxing_anon muxing;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_state_s
+ {
+ /// int
+ public int state;
+ public hb_state_param_u param;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct Anonymous_a0a59d69_d9a4_4003_a198_f7c51511e31d
+ {
+ /// int
+ [FieldOffset(0)]
+ public int ac3;
+
+ /// int
+ [FieldOffset(0)]
+ public int dca;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_mixdown_s
+ {
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string human_readable_name;
+
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string internal_name;
+
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string short_name;
+
+ /// int
+ public int amixdown;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_fifo_s
+ {
+ /// hb_lock_t*
+ public IntPtr @lock;
+
+ /// uint32_t->unsigned int
+ public uint capacity;
+
+ /// uint32_t->unsigned int
+ public uint size;
+
+ /// uint32_t->unsigned int
+ public uint buffer_size;
+
+ /// hb_buffer_t*
+ public IntPtr first;
+
+ /// hb_buffer_t*
+ public IntPtr last;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_lock_s
+ {
+ }
+
+ // Only called by detect_comb at the moment
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_buffer_s
+ {
+ /// int
+ public int size;
+
+ /// int
+ public int alloc;
+
+ /// uint8_t*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string data;
+
+ /// int
+ public int cur;
+
+ /// int64_t->int
+ public long sequence;
+
+ public hb_buffer_type_anon type;
+
+ /// int
+ public int id;
+
+ /// int64_t->int
+ public long start;
+
+ /// int64_t->int
+ public long stop;
+
+ public long pcr;
+
+ public byte discontinuity;
+
+ /// int
+ public int new_chap;
+
+ /// uint8_t->unsigned char
+ public byte frametype;
+
+ // Given uint by default, probably should be ushort?
+ /// uint16_t->unsigned int
+ public uint flags;
+
+ /// int64_t->int
+ public long renderOffset;
+
+ /// int
+ public int x;
+
+ /// int
+ public int y;
+
+ /// int
+ public int width;
+
+ /// int
+ public int height;
+
+ /// hb_buffer_t*
+ public IntPtr sub;
+
+ /// hb_buffer_t*
+ public IntPtr next;
+ }
+
+ public enum hb_buffer_type_anon
+ {
+ AUDIO_BUF,
+
+ VIDEO_BUF,
+
+ SUBTITLE_BUF,
+
+ OTHER_BUF
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_mux_data_s
+ {
+ /// MP4TrackId->uint32_t->unsigned int
+ public uint track;
+
+ /// uint8_t->unsigned char
+ public byte subtitle;
+
+ /// int
+ public int sub_format;
+
+ /// uint64_t->unsigned int
+ public ulong sum_dur;
+ }
+
+ // Not referred to anywhere
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_interjob_s
+ {
+ /// int
+ public int last_job;
+
+ /// int
+ public int frame_count;
+
+ public int out_frame_count;
+
+ /// uint64_t->unsigned int
+ public ulong total_time;
+
+ /// int
+ public int vrate;
+
+ /// int
+ public int vrate_base;
+
+ /// hb_subtitle_t*
+ public IntPtr select_subtitle;
+ }
+
+ /// Return Type: void
+ ///param0: void*
+ public delegate void hb_thread_s_function(IntPtr param0);
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_thread_s
+ {
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string name;
+
+ /// int
+ public int priority;
+
+ /// hb_thread_s_function
+ public hb_thread_s_function AnonymousMember1;
+
+ /// void*
+ public IntPtr arg;
+
+ /// hb_lock_t*
+ public IntPtr @lock;
+
+ /// int
+ public int exited;
+
+ /// pthread_t->ptw32_handle_t->Anonymous_55c509b5_bbf2_4788_a684_ac1bd0056655
+ public ptw32_handle_t thread;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ptw32_handle_t
+ {
+ /// void*
+ public IntPtr p;
+
+ /// unsigned int
+ public uint x;
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void LoggingCallback(string message);
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs
new file mode 100644
index 000000000..8d097b33e
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs
@@ -0,0 +1,99 @@
+namespace HandBrake.Interop
+{
+ public partial class NativeConstants
+ {
+ public const int HB_ACODEC_MASK = 0x0000FF00;
+ public const int HB_ACODEC_FAAC = 0x00000100;
+ public const int HB_ACODEC_LAME = 0x00000200;
+ public const int HB_ACODEC_VORBIS = 0x00000400;
+ public const int HB_ACODEC_AC3 = 0x00000800;
+ public const int HB_ACODEC_MPGA = 0x00001000;
+ public const int HB_ACODEC_LPCM = 0x00002000;
+ public const int HB_ACODEC_DCA = 0x00004000;
+ public const int HB_ACODEC_FFMPEG = 0x00008000;
+ public const int HB_ACODEC_CA_AAC = 0x00010000;
+ public const int HB_ACODEC_PASS_FLAG = 0x40000000;
+ public const int HB_ACODEC_PASS_MASK = HB_ACODEC_AC3 | HB_ACODEC_DCA;
+ public const int HB_ACODEC_AC3_PASS = HB_ACODEC_AC3 | HB_ACODEC_PASS_FLAG;
+ public const int HB_ACODEC_DCA_PASS = HB_ACODEC_DCA | HB_ACODEC_PASS_FLAG;
+ public const int HB_ACODEC_ANY = HB_ACODEC_MASK | HB_ACODEC_PASS_FLAG;
+
+ public const int HB_SUBSTREAM_BD_TRUEHD = 0x72;
+ public const int HB_SUBSTREAM_BD_AC3 = 0x76;
+ public const int HB_SUBSTREAM_BD_DTSHD = 0x72;
+ public const int HB_SUBSTREAM_BD_DTS = 0x71;
+
+ public const int HB_AMIXDOWN_DCA_FORMAT_MASK = 0x00FFF000;
+ public const int HB_AMIXDOWN_A52_FORMAT_MASK = 0x00000FF0;
+ public const int HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK = 0x0000000F;
+ public const int HB_AMIXDOWN_MONO = 0x01000001;
+ public const int HB_AMIXDOWN_STEREO = 0x02002022;
+ public const int HB_AMIXDOWN_DOLBY = 0x042070A2;
+ public const int HB_AMIXDOWN_DOLBYPLII = 0x084094A2;
+ public const int HB_AMIXDOWN_6CH = 0x10089176;
+
+ public const int HB_INPUT_CH_LAYOUT_MONO = 0x0110010;
+ public const int HB_INPUT_CH_LAYOUT_STEREO = 0x0220020;
+ public const int HB_INPUT_CH_LAYOUT_DOLBY = 0x0320031;
+ public const int HB_INPUT_CH_LAYOUT_3F = 0x0430030;
+ public const int HB_INPUT_CH_LAYOUT_2F1R = 0x0521021;
+ public const int HB_INPUT_CH_LAYOUT_3F1R = 0x0631031;
+ public const int HB_INPUT_CH_LAYOUT_2F2R = 0x0722022;
+ public const int HB_INPUT_CH_LAYOUT_3F2R = 0x0832032;
+ public const int HB_INPUT_CH_LAYOUT_4F2R = 0x0942042;
+ public const int HB_INPUT_CH_LAYOUT_3F4R = 0x0a34034;
+ public const int HB_INPUT_CH_LAYOUT_HAS_LFE = 0x0000100;
+ public const int HB_INPUT_CH_LAYOUT_DISCRETE_FRONT_MASK = 0x00F0000;
+ public const int HB_INPUT_CH_LAYOUT_DISCRETE_REAR_MASK = 0x000F000;
+ public const int HB_INPUT_CH_LAYOUT_DISCRETE_LFE_MASK = 0x0000F00;
+ public const int HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK = 0xFFFF0FF;
+ public const int HB_INPUT_CH_LAYOUT_ENCODED_FRONT_MASK = 0x00000F0;
+ public const int HB_INPUT_CH_LAYOUT_ENCODED_REAR_MASK = 0x000000F;
+
+ public const int HB_VCODEC_MASK = 0x0000FF;
+ public const int HB_VCODEC_X264 = 0x000001;
+ public const int HB_VCODEC_THEORA = 0x000002;
+ public const int HB_VCODEC_FFMPEG_MPEG4 = 0x000010;
+ public const int HB_VCODEC_FFMPEG = HB_VCODEC_FFMPEG_MPEG4;
+ public const int HB_VCODEC_FFMPEG_MPEG2 = 0x000020;
+ public const int HB_VCODEC_FFMPEG_MASK = 0x0000F0;
+
+ public const int HB_MUX_MASK = 0xFF0000;
+ public const int HB_MUX_MP4 = 0x010000;
+ public const int HB_MUX_MKV = 0x200000;
+
+ public const int HBTF_NO_IDR = 1 << 0;
+
+ public const int HB_STATE_IDLE = 1;
+ public const int HB_STATE_SCANNING = 2;
+ public const int HB_STATE_SCANDONE = 4;
+ public const int HB_STATE_WORKING = 8;
+ public const int HB_STATE_PAUSED = 16;
+ public const int HB_STATE_WORKDONE = 32;
+ public const int HB_STATE_MUXING = 64;
+
+ public const int HB_ERROR_NONE = 0;
+ public const int HB_ERROR_CANCELED = 1;
+ public const int HB_ERROR_UNKNOWN = 2;
+
+ public const int AUDIO_F_DOLBY = 1 << 31;
+
+ public const int HB_FRAME_IDR = 0x01;
+ public const int HB_FRAME_I = 0x02;
+ public const int HB_FRAME_AUDIO = 0x04;
+ public const int HB_FRAME_P = 0x10;
+ public const int HB_FRAME_B = 0x20;
+ public const int HB_FRAME_BREF = 0x40;
+ public const int HB_FRAME_KEY = 0x0F;
+ public const int HB_FRAME_REF = 0xF0;
+
+ public const int HB_CONFIG_MAX_SIZE = 8192;
+
+ public const int HB_FILTER_DETELECINE = 1;
+ public const int HB_FILTER_DEINTERLACE = 2;
+ public const int HB_FILTER_DEBLOCK = 3;
+ public const int HB_FILTER_DENOISE = 4;
+ public const int HB_FILTER_DECOMB = 5;
+ public const int HB_FILTER_ROTATE = 6;
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_audio.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_audio.cs
new file mode 100644
index 000000000..6992d1ffd
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_audio.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_audio_s
+ {
+ /// int
+ public int id;
+
+ /// hb_audio_config_t->hb_audio_config_s
+ public hb_audio_config_s config;
+
+ // Padding for the part of the struct we don't care about marshaling.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = MarshalingConstants.AudioPaddingBytes, ArraySubType = UnmanagedType.U1)]
+ public byte[] padding;
+
+ /// Anonymous_e6c7b779_b5a3_4e80_9fa8_13619d14f545
+ //public Anonymous_e6c7b779_b5a3_4e80_9fa8_13619d14f545 priv;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_audio_config_s
+ {
+ public hb_audio_config_output_s output;
+ public hb_audio_config_input_s input;
+
+ /// Anonymous_a0a59d69_d9a4_4003_a198_f7c51511e31d
+ public Anonymous_a0a59d69_d9a4_4003_a198_f7c51511e31d flags;
+
+ public hb_audio_config_lang_s lang;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_audio_config_output_s
+ {
+ /// int
+ public int track;
+
+ /// uint32_t->unsigned int
+ public uint codec;
+
+ /// int
+ public int samplerate;
+
+ /// int
+ public int bitrate;
+
+ /// int
+ public int mixdown;
+
+ /// double
+ public double dynamic_range_compression;
+
+ public double gain;
+
+ /// char*
+ //[MarshalAs(UnmanagedType.LPStr)]
+ //public string name;
+
+ public IntPtr name;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_audio_config_input_s
+ {
+ /// int
+ public int track;
+
+ /// uint32_t->unsigned int
+ public uint codec;
+
+ public uint reg_desc;
+
+ public uint stream_type;
+
+ public uint substream_type;
+
+ /// uint32_t->unsigned int
+ public uint codec_param;
+
+ /// uint32_t->unsigned int
+ public uint version;
+
+ /// uint32_t->unsigned int
+ public uint mode;
+
+ /// int
+ public int samplerate;
+
+ /// int
+ public int bitrate;
+
+ /// int
+ public int channel_layout;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct hb_audio_config_lang_s
+ {
+ /// char[1024]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string description;
+
+ /// char[1024]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string simple;
+
+ /// char[4]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
+ public string iso639_2;
+
+ /// uint8_t->unsigned char
+ public byte type;
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_chapter_s.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_chapter_s.cs
new file mode 100644
index 000000000..fd3762398
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_chapter_s.cs
@@ -0,0 +1,48 @@
+using System.Runtime.InteropServices;
+
+namespace HandBrake.Interop
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct hb_chapter_s
+ {
+ /// int
+ public int index;
+
+ /// int
+ public int pgcn;
+
+ /// int
+ public int pgn;
+
+ /// int
+ public int cell_start;
+
+ /// int
+ public int cell_end;
+
+ /// int
+ public ulong block_start;
+
+ /// int
+ public ulong block_end;
+
+ /// int
+ public ulong block_count;
+
+ /// int
+ public int hours;
+
+ /// int
+ public int minutes;
+
+ /// int
+ public int seconds;
+
+ /// uint64_t->unsigned int
+ public ulong duration;
+
+ /// char[1024]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string title;
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_handle_s.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_handle_s.cs
new file mode 100644
index 000000000..dd56681bb
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_handle_s.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace HandBrake.Interop
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct hb_handle_s
+ {
+ public int id;
+
+ /// int
+ public int build;
+
+ /// char[32]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
+ public string version;
+
+ /// hb_thread_t*
+ public IntPtr update_thread;
+
+ /// int
+ public int die;
+
+ /// hb_thread_t*
+ public IntPtr main_thread;
+
+ /// int
+ public int pid;
+
+ /// hb_list_t*
+ public IntPtr list_title;
+
+ /// hb_thread_t*
+ public IntPtr scan_thread;
+
+ /// hb_list_t*
+ public IntPtr jobs;
+
+ /// hb_job_t*
+ public IntPtr current_job;
+
+ /// int
+ public int job_count;
+
+ /// int
+ public int job_count_permanent;
+
+ /// int
+ public int work_die;
+
+ /// int
+ public int work_error;
+
+ /// hb_thread_t*
+ public IntPtr work_thread;
+
+ // This is REMOVED in the latest HB SVN
+ public int cpu_count;
+
+ /// hb_lock_t*
+ public IntPtr state_lock;
+
+ /// hb_state_t->hb_state_s
+ public hb_state_s state;
+
+ /// int
+ public int paused;
+
+ /// hb_lock_t*
+ public IntPtr pause_lock;
+
+ /// int
+ public int scanCount;
+
+ /// hb_interjob_t*
+ public IntPtr interjob;
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs
new file mode 100644
index 000000000..c12352e04
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs
@@ -0,0 +1,149 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace HandBrake.Interop
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct hb_job_s
+ {
+ /// int
+ public int sequence_id;
+
+ /// hb_title_t*
+ public IntPtr title;
+
+ public int feature;
+
+ /// int
+ public int chapter_start;
+
+ /// int
+ public int chapter_end;
+
+ /// int
+ public int chapter_markers;
+
+ /// int[4]
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.I4)]
+ public int[] crop;
+
+ /// int
+ public int deinterlace;
+
+ /// hb_list_t*
+ public IntPtr filters;
+
+ /// int
+ public int width;
+
+ /// int
+ public int height;
+
+ /// int
+ public int keep_ratio;
+
+ /// int
+ public int grayscale;
+
+ public hb_anamorphic_substruct anamorphic;
+
+ public int modulus;
+
+ /// int
+ public int maxWidth;
+
+ /// int
+ public int maxHeight;
+
+ /// int
+ public int vcodec;
+
+ /// float
+ public float vquality;
+
+ /// int
+ public int vbitrate;
+
+ public int pfr_vrate;
+
+ public int pfr_vrate_base;
+
+ /// int
+ public int vrate;
+
+ /// int
+ public int vrate_base;
+
+ /// int
+ public int cfr;
+
+ /// int
+ public int pass;
+
+ /// char*
+ //[MarshalAs(UnmanagedType.LPStr)]
+ //public string x264opts;
+
+ public IntPtr advanced_opts;
+
+ /// int
+ public int areBframes;
+
+ /// int
+ public int color_matrix;
+
+ /// hb_list_t*
+ public IntPtr list_audio;
+
+ /// hb_list_t*
+ public IntPtr list_subtitle;
+
+ /// int
+ public int mux;
+
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string file;
+
+ /// int
+ public int largeFileSize;
+
+ /// int
+ public int mp4_optimize;
+
+ /// int
+ public int ipod_atom;
+
+ /// int
+ public int indepth_scan;
+
+ /// hb_subtitle_config_t->hb_subtitle_config_s
+ public hb_subtitle_config_s select_subtitle_config;
+
+ /// int
+ public int angle;
+
+ public int frame_to_start;
+
+ public long pts_to_start;
+
+ /// int
+ public int frame_to_stop;
+
+ /// int64_t->int
+ public long pts_to_stop;
+
+ /// int
+ public int start_at_preview;
+
+ /// int
+ public int seek_points;
+
+ /// uint32_t->unsigned int
+ public uint frames_to_skip;
+
+ // Padding for the part of the struct we don't care about marshaling.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = MarshalingConstants.JobPaddingBytes, ArraySubType = UnmanagedType.U1)]
+ public byte[] padding;
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_subtitle.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_subtitle.cs
new file mode 100644
index 000000000..f5a830cc4
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_subtitle.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace HandBrake.Interop
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct hb_subtitle_s
+ {
+ /// int
+ public int id;
+
+ /// int
+ public int track;
+
+ /// hb_subtitle_config_t->hb_subtitle_config_s
+ public hb_subtitle_config_s config;
+
+ /// hb_subtitle_s_subtype
+ public hb_subtitle_s_subtype format;
+
+ /// hb_subtitle_s_subsource
+ public hb_subtitle_s_subsource source;
+
+ /// char[1024]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string lang;
+
+ /// char[4]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
+ public string iso639_2;
+
+ /// uint8_t->unsigned char
+ public byte type;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16, ArraySubType = UnmanagedType.U4)]
+ public uint[] palette;
+
+ public int width;
+
+ public int height;
+
+ public IntPtr extradata;
+
+ public int extradata_size;
+
+ /// int
+ public int hits;
+
+ /// int
+ public int forced_hits;
+
+ /// hb_fifo_t*
+ public IntPtr fifo_in;
+
+ /// hb_fifo_t*
+ public IntPtr fifo_raw;
+
+ /// hb_fifo_t*
+ public IntPtr fifo_sync;
+
+ /// hb_fifo_t*
+ public IntPtr fifo_out;
+
+ /// hb_mux_data_t*
+ public IntPtr mux_data;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct hb_subtitle_config_s
+ {
+ /// hb_subtitle_config_s_subdest
+ public hb_subtitle_config_s_subdest dest;
+
+ /// int
+ public int force;
+
+ /// int
+ public int default_track;
+
+ /// char[128]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
+ public string src_filename;
+
+ /// char[40]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
+ public string src_codeset;
+
+ /// int64_t->int
+ public long offset;
+ }
+
+ public enum hb_subtitle_config_s_subdest
+ {
+ RENDERSUB,
+
+ PASSTHRUSUB,
+ }
+
+ public enum hb_subtitle_s_subtype
+ {
+ PICTURESUB,
+
+ TEXTSUB,
+ }
+
+ public enum hb_subtitle_s_subsource
+ {
+ VOBSUB,
+
+ SRTSUB,
+
+ CC608SUB,
+
+ CC708SUB,
+
+ UTF8SUB,
+
+ TX3GSUB,
+
+ SSASUB
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_title_s.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_title_s.cs
new file mode 100644
index 000000000..856cdcfbb
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_title_s.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace HandBrake.Interop
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct hb_title_s
+ {
+ /// Anonymous_990d28ea_6cf3_4fbc_8143_4df9513e9550
+ public hb_title_type_anon type;
+
+ public uint reg_desc;
+
+ /// char[1024]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string dvd;
+
+ /// char[1024]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
+ public string name;
+
+ /// int
+ public int index;
+
+ /// int
+ public int vts;
+
+ /// int
+ public int ttn;
+
+ /// int
+ public int cell_start;
+
+ /// int
+ public int cell_end;
+
+ /// int
+ public ulong block_start;
+
+ /// int
+ public ulong block_end;
+
+ /// int
+ public ulong block_count;
+
+ /// int
+ public int angle_count;
+
+ /// int
+ public int hours;
+
+ /// int
+ public int minutes;
+
+ /// int
+ public int seconds;
+
+ /// uint64_t->unsigned int
+ public ulong duration;
+
+ /// double
+ public double aspect;
+
+ /// double
+ public double container_aspect;
+
+ /// int
+ public int width;
+
+ /// int
+ public int height;
+
+ /// int
+ public int pixel_aspect_width;
+
+ /// int
+ public int pixel_aspect_height;
+
+ /// int
+ public int rate;
+
+ /// int
+ public int rate_base;
+
+ /// int[4]
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.I4)]
+ public int[] crop;
+
+ //public fixed int crop[4];
+
+ /// Anonymous_618ebeca_0ad9_4a71_9a49_18e50ac2e9db
+ public Anonymous_618ebeca_0ad9_4a71_9a49_18e50ac2e9db demuxer;
+
+ /// int
+ public int detected_interlacing;
+
+ public int pcr_pid;
+
+ /// int
+ public int video_id;
+
+ /// int
+ public int video_codec;
+
+ public uint video_stream_type;
+
+ /// int
+ public int video_codec_param;
+
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string video_codec_name;
+
+ /// int
+ public int video_bitrate;
+
+ /// char*
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string container_name;
+
+ /// int
+ public int data_rate;
+
+ /// hb_metadata_t*
+ public IntPtr metadata;
+
+ /// hb_list_t*
+ public IntPtr list_chapter;
+
+ /// hb_list_t*
+ public IntPtr list_audio;
+
+ /// hb_list_t*
+ public IntPtr list_subtitle;
+
+ /// hb_list_t*
+ public IntPtr list_attachment;
+
+ /// hb_job_t*
+ public IntPtr job;
+
+ /// uint32_t->unsigned int
+ public uint flags;
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs
new file mode 100644
index 000000000..4102e5eb7
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs
@@ -0,0 +1,144 @@
+namespace HandBrake.Interop
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Runtime.InteropServices;
+
+ /// <summary>
+ /// Helper utilities for native interop.
+ /// </summary>
+ public static class InteropUtilities
+ {
+ /// <summary>
+ /// Reads the given native structure pointer.
+ /// </summary>
+ /// <typeparam name="T">The type to convert the structure to.</typeparam>
+ /// <param name="structPtr">The pointer to the native structure.</param>
+ /// <returns>The converted structure.</returns>
+ public static T ReadStructure<T>(IntPtr structPtr)
+ {
+ return (T)Marshal.PtrToStructure(structPtr, typeof(T));
+ }
+
+ /// <summary>
+ /// Converts the given native HandBrake list to a managed list.
+ /// </summary>
+ /// <typeparam name="T">The type of structure in the list.</typeparam>
+ /// <param name="listPtr">The pointer to the native list.</param>
+ /// <returns>The converted managed list.</returns>
+ public static List<T> ConvertList<T>(IntPtr listPtr)
+ {
+ List<T> returnList = new List<T>();
+ hb_list_s itemList = ReadStructure<hb_list_s>(listPtr);
+
+ for (int i = 0; i < itemList.items_count; i++)
+ {
+ IntPtr itemPtr = Marshal.ReadIntPtr(itemList.items, i * Marshal.SizeOf(typeof(IntPtr)));
+ returnList.Add(ReadStructure<T>(itemPtr));
+ }
+
+ return returnList;
+ }
+
+ /// <summary>
+ /// Creats a new, empty native HandBrake list.
+ /// </summary>
+ /// <returns>The new native list.</returns>
+ public static NativeList CreateNativeList(int capacity)
+ {
+ NativeList returnList = new NativeList();
+ int intSize = Marshal.SizeOf(typeof(IntPtr));
+
+ IntPtr nativeListInternal = Marshal.AllocHGlobal(capacity * intSize);
+ returnList.AllocatedMemory.Add(nativeListInternal);
+
+ hb_list_s nativeListStruct = new hb_list_s();
+ nativeListStruct.items = nativeListInternal;
+ nativeListStruct.items_alloc = capacity;
+ nativeListStruct.items_count = 0;
+
+ IntPtr nativeListStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_list_s)));
+ Marshal.StructureToPtr(nativeListStruct, nativeListStructPtr, false);
+
+ returnList.ListPtr = nativeListStructPtr;
+ return returnList;
+ }
+
+ /// <summary>
+ /// Creates a native HandBrake list from the given managed list of pointers.
+ /// </summary>
+ /// <param name="list">The managed list to convert.</param>
+ /// <returns>The converted native list.</returns>
+ public static NativeList CreateIntPtrList(List<IntPtr> list)
+ {
+ NativeList returnList = new NativeList();
+ int intSize = Marshal.SizeOf(typeof(IntPtr));
+
+ IntPtr nativeListInternal = Marshal.AllocHGlobal(list.Count * intSize);
+ returnList.AllocatedMemory.Add(nativeListInternal);
+ for (int i = 0; i < list.Count; i++)
+ {
+ Marshal.WriteIntPtr(nativeListInternal, i * intSize, list[i]);
+ }
+
+ hb_list_s nativeListStruct = new hb_list_s();
+ nativeListStruct.items = nativeListInternal;
+ nativeListStruct.items_alloc = list.Count;
+ nativeListStruct.items_count = list.Count;
+
+ IntPtr nativeListStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_list_s)));
+ Marshal.StructureToPtr(nativeListStruct, nativeListStructPtr, false);
+
+ returnList.ListPtr = nativeListStructPtr;
+ return returnList;
+ }
+
+ /// <summary>
+ /// Creates a native HandBrake list from the given managed list of structures.
+ /// </summary>
+ /// <typeparam name="T">The type of structures in the list.</typeparam>
+ /// <param name="list">The managed list to convert.</param>
+ /// <returns>The converted native list.</returns>
+ public static NativeList ConvertListBack<T>(List<T> list)
+ {
+ NativeList returnList = new NativeList();
+ int intSize = Marshal.SizeOf(typeof(IntPtr));
+
+ IntPtr nativeListInternal = Marshal.AllocHGlobal(list.Count * intSize);
+ returnList.AllocatedMemory.Add(nativeListInternal);
+ for (int i = 0; i < list.Count; i++)
+ {
+ IntPtr itemPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)));
+ returnList.AllocatedMemory.Add(itemPtr);
+ Marshal.StructureToPtr(list[i], itemPtr, false);
+
+ Marshal.WriteIntPtr(nativeListInternal, i * intSize, itemPtr);
+ }
+
+ hb_list_s nativeListStruct = new hb_list_s();
+ nativeListStruct.items = nativeListInternal;
+ nativeListStruct.items_alloc = list.Count;
+ nativeListStruct.items_count = list.Count;
+
+ IntPtr nativeListStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_list_s)));
+ Marshal.StructureToPtr(nativeListStruct, nativeListStructPtr, false);
+
+ returnList.ListPtr = nativeListStructPtr;
+ return returnList;
+ }
+
+ /// <summary>
+ /// Frees all the memory locations in the given list.
+ /// </summary>
+ /// <param name="memoryList">The list of memory locations to free.</param>
+ public static void FreeMemory(List<IntPtr> memoryList)
+ {
+ foreach (IntPtr memoryLocation in memoryList)
+ {
+ Marshal.FreeHGlobal(memoryLocation);
+ }
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Language.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Language.cs
new file mode 100644
index 000000000..2bc4ff329
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Language.cs
@@ -0,0 +1,38 @@
+namespace HandBrake.Interop
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// Represents a language.
+ /// </summary>
+ public class Language
+ {
+ /// <summary>
+ /// Initializes a new instance of the Language class.
+ /// </summary>
+ /// <param name="code">The code for the langauge.</param>
+ public Language(string code)
+ {
+ this.Code = code;
+ }
+
+ /// <summary>
+ /// Gets the friendly name of the language.
+ /// </summary>
+ public string Name
+ {
+ get
+ {
+ return LanguageCodes.Decode(this.Code);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the language code.
+ /// </summary>
+ public string Code { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/LanguageCodes.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/LanguageCodes.cs
new file mode 100644
index 000000000..2e0bac7b4
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/LanguageCodes.cs
@@ -0,0 +1,255 @@
+namespace HandBrake.Interop
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// Contains utilities for converting language codes.
+ /// </summary>
+ public static class LanguageCodes
+ {
+ /// <summary>
+ /// The map of language codes to friendly names.
+ /// </summary>
+ private static Dictionary<string, string> languageMap;
+
+ /// <summary>
+ /// Gets the map of language codes to friendly names.
+ /// </summary>
+ private static Dictionary<string, string> LanguageMap
+ {
+ get
+ {
+ if (languageMap == null)
+ {
+ languageMap = new Dictionary<string, string>
+ {
+ {"und", "Unspecified"},
+ {"eng", "English"},
+ {"deu", "Deutsch"},
+ {"fra", "Français"},
+ {"spa", "Español"},
+ {"rus", "Russian"},
+ {"aar", "Afar"},
+ {"abk", "Abkhazian"},
+ {"afr", "Afrikaans"},
+ {"aka", "Akan"},
+ {"sqi", "Albanian"},
+ {"amh", "Amharic"},
+ {"ara", "Arabic"},
+ {"arg", "Aragonese"},
+ {"hye", "Armenian"},
+ {"asm", "Assamese"},
+ {"ava", "Avaric"},
+ {"ave", "Avestan"},
+ {"aym", "Aymara"},
+ {"aze", "Azerbaijani"},
+ {"bak", "Bashkir"},
+ {"bam", "Bambara"},
+ {"eus", "Basque"},
+ {"bel", "Belarusian"},
+ {"ben", "Bengali"},
+ {"bih", "Bihari"},
+ {"bis", "Bislama"},
+ {"bos", "Bosnian"},
+ {"bre", "Breton"},
+ {"bul", "Bulgarian"},
+ {"mya", "Burmese"},
+ {"cat", "Catalan"},
+ {"cha", "Chamorro"},
+ {"che", "Chechen"},
+ {"zho", "Chinese"},
+ {"chu", "Church Slavic"},
+ {"chv", "Chuvash"},
+ {"cor", "Cornish"},
+ {"cos", "Corsican"},
+ {"cre", "Cree"},
+ {"ces", "Czech"},
+ {"dan", "Dansk"},
+ {"div", "Divehi"},
+ {"nld", "Nederlands"},
+ {"dzo", "Dzongkha"},
+ {"epo", "Esperanto"},
+ {"est", "Estonian"},
+ {"ewe", "Ewe"},
+ {"fao", "Faroese"},
+ {"fij", "Fijian"},
+ {"fin", "Suomi"},
+ {"fry", "Western Frisian"},
+ {"ful", "Fulah"},
+ {"kat", "Georgian"},
+ {"gla", "Gaelic (Scots)"},
+ {"gle", "Irish"},
+ {"glg", "Galician"},
+ {"glv", "Manx"},
+ {"ell", "Greek Modern"},
+ {"grn", "Guarani"},
+ {"guj", "Gujarati"},
+ {"hat", "Haitian"},
+ {"hau", "Hausa"},
+ {"heb", "Hebrew"},
+ {"her", "Herero"},
+ {"hin", "Hindi"},
+ {"hmo", "Hiri Motu"},
+ {"hun", "Magyar"},
+ {"ibo", "Igbo"},
+ {"isl", "Islenska"},
+ {"ido", "Ido"},
+ {"iii", "Sichuan Yi"},
+ {"iku", "Inuktitut"},
+ {"ile", "Interlingue"},
+ {"ina", "Interlingua"},
+ {"ind", "Indonesian"},
+ {"ipk", "Inupiaq"},
+ {"ita", "Italiano"},
+ {"jav", "Javanese"},
+ {"jpn", "Japanese"},
+ {"kal", "Kalaallisut"},
+ {"kan", "Kannada"},
+ {"kas", "Kashmiri"},
+ {"kau", "Kanuri"},
+ {"kaz", "Kazakh"},
+ {"khm", "Central Khmer"},
+ {"kik", "Kikuyu"},
+ {"kin", "Kinyarwanda"},
+ {"kir", "Kirghiz"},
+ {"kom", "Komi"},
+ {"kon", "Kongo"},
+ {"kor", "Korean"},
+ {"kua", "Kuanyama"},
+ {"kur", "Kurdish"},
+ {"lao", "Lao"},
+ {"lat", "Latin"},
+ {"lav", "Latvian"},
+ {"lim", "Limburgan"},
+ {"lin", "Lingala"},
+ {"lit", "Lithuanian"},
+ {"ltz", "Luxembourgish"},
+ {"lub", "Luba-Katanga"},
+ {"lug", "Ganda"},
+ {"mkd", "Macedonian"},
+ {"mah", "Marshallese"},
+ {"mal", "Malayalam"},
+ {"mri", "Maori"},
+ {"mar", "Marathi"},
+ {"msa", "Malay"},
+ {"mlg", "Malagasy"},
+ {"mlt", "Maltese"},
+ {"mol", "Moldavian"},
+ {"mon", "Mongolian"},
+ {"nau", "Nauru"},
+ {"nav", "Navajo"},
+ {"nbl", "Ndebele, South"},
+ {"nde", "Ndebele, North"},
+ {"ndo", "Ndonga"},
+ {"nep", "Nepali"},
+ {"nno", "Norwegian Nynorsk"},
+ {"nob", "Norwegian Bokmål"},
+ {"nor", "Norsk"},
+ {"nya", "Chichewa; Nyanja"},
+ {"oci", "Occitan"},
+ {"oji", "Ojibwa"},
+ {"ori", "Oriya"},
+ {"orm", "Oromo"},
+ {"oss", "Ossetian"},
+ {"pan", "Panjabi"},
+ {"fas", "Persian"},
+ {"pli", "Pali"},
+ {"pol", "Polish"},
+ {"por", "Portugues"},
+ {"pus", "Pushto"},
+ {"que", "Quechua"},
+ {"roh", "Romansh"},
+ {"ron", "Romanian"},
+ {"run", "Rundi"},
+ {"sag", "Sango"},
+ {"san", "Sanskrit"},
+ {"srp", "Serbian"},
+ {"hrv", "Hrvatski"},
+ {"sin", "Sinhala"},
+ {"slk", "Slovak"},
+ {"slv", "Slovenian"},
+ {"sme", "Northern Sami"},
+ {"smo", "Samoan"},
+ {"sna", "Shona"},
+ {"snd", "Sindhi"},
+ {"som", "Somali"},
+ {"sot", "Sotho Southern"},
+ {"srd", "Sardinian"},
+ {"ssw", "Swati"},
+ {"sun", "Sundanese"},
+ {"swa", "Swahili"},
+ {"swe", "Svenska"},
+ {"tah", "Tahitian"},
+ {"tam", "Tamil"},
+ {"tat", "Tatar"},
+ {"tel", "Telugu"},
+ {"tgk", "Tajik"},
+ {"tgl", "Tagalog"},
+ {"tha", "Thai"},
+ {"bod", "Tibetan"},
+ {"tir", "Tigrinya"},
+ {"ton", "Tonga"},
+ {"tsn", "Tswana"},
+ {"tso", "Tsonga"},
+ {"tuk", "Turkmen"},
+ {"tur", "Turkish"},
+ {"twi", "Twi"},
+ {"uig", "Uighur"},
+ {"ukr", "Ukrainian"},
+ {"urd", "Urdu"},
+ {"uzb", "Uzbek"},
+ {"ven", "Venda"},
+ {"vie", "Vietnamese"},
+ {"vol", "Volapük"},
+ {"cym", "Welsh"},
+ {"wln", "Walloon"},
+ {"wol", "Wolof"},
+ {"xho", "Xhosa"},
+ {"yid", "Yiddish"},
+ {"yor", "Yoruba"},
+ {"zha", "Zhuang"},
+ {"zul", "Zulu"}
+ };
+ }
+
+ return languageMap;
+ }
+ }
+
+ /// <summary>
+ /// Gets a list of all languages.
+ /// </summary>
+ public static IList<Language> Languages
+ {
+ get
+ {
+ List<Language> languages = new List<Language>();
+
+ foreach (string languageCode in LanguageMap.Keys)
+ {
+ languages.Add(new Language(languageCode));
+ }
+
+ return languages;
+ }
+ }
+
+ /// <summary>
+ /// Gives the friendly name of the language with the given code.
+ /// </summary>
+ /// <param name="languageCode">The language code.</param>
+ /// <returns>The friendly name of the language.</returns>
+ public static string Decode(string languageCode)
+ {
+ if (LanguageMap.ContainsKey(languageCode))
+ {
+ return LanguageMap[languageCode];
+ }
+
+ return "Unknown";
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/MarshalingConstants.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/MarshalingConstants.cs
new file mode 100644
index 000000000..67fd8d177
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/MarshalingConstants.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public static class MarshalingConstants
+ {
+#if X64
+ public const int JobPaddingBytes = 24696;
+ public const int AudioPaddingBytes = 24640;
+#else
+ public const int JobPaddingBytes = 24644;
+ public const int AudioPaddingBytes = 24608;
+#endif
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/MessageLoggedEventArgs.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/MessageLoggedEventArgs.cs
new file mode 100644
index 000000000..6976fedc6
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/MessageLoggedEventArgs.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class MessageLoggedEventArgs : EventArgs
+ {
+ public string Message { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Cropping.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Cropping.cs
new file mode 100644
index 000000000..2b95a0e11
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Cropping.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class Cropping
+ {
+ public int Top { get; set; }
+ public int Bottom { get; set; }
+ public int Left { get; set; }
+ public int Right { get; set; }
+
+ public Cropping Clone()
+ {
+ return new Cropping
+ {
+ Top = this.Top,
+ Bottom = this.Bottom,
+ Left = this.Left,
+ Right = this.Right
+ };
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/EncodeJob.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/EncodeJob.cs
new file mode 100644
index 000000000..850f6ea2e
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/EncodeJob.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Serialization;
+
+namespace HandBrake.Interop
+{
+ public class EncodeJob
+ {
+ public SourceType SourceType { get; set; }
+ public string SourcePath { get; set; }
+
+ /// <summary>
+ /// Gets or sets the 1-based index of the title to encode.
+ /// </summary>
+ public int Title { get; set; }
+
+ /// <summary>
+ /// Gets or sets the angle to encode. 0 for default, 1+ for specified angle.
+ /// </summary>
+ public int Angle { get; set; }
+
+ public VideoRangeType RangeType { get; set; }
+ public int ChapterStart { get; set; }
+ public int ChapterEnd { get; set; }
+
+ public double SecondsStart { get; set; }
+ public double SecondsEnd { get; set; }
+
+ public int FramesStart { get; set; }
+ public int FramesEnd { get; set; }
+
+ /// <summary>
+ /// Gets or sets the list of chosen audio tracks (1-based)
+ /// </summary>
+ public List<int> ChosenAudioTracks { get; set; }
+ public Subtitles Subtitles { get; set; }
+ public bool UseDefaultChapterNames { get; set; }
+ public List<string> CustomChapterNames { get; set; }
+
+ public string OutputPath { get; set; }
+
+ public EncodingProfile EncodingProfile { get; set; }
+
+ // The length of video to encode.
+ [XmlIgnore]
+ public TimeSpan Length { get; set; }
+
+ [XmlElement("Length")]
+ public string XmlLength
+ {
+ get { return this.Length.ToString(); }
+ set { this.Length = TimeSpan.Parse(value); }
+ }
+
+ public EncodeJob Clone()
+ {
+ EncodeJob clone = new EncodeJob
+ {
+ SourceType = this.SourceType,
+ SourcePath = this.SourcePath,
+ Title = this.Title,
+ Angle = this.Angle,
+ RangeType = this.RangeType,
+ ChapterStart = this.ChapterStart,
+ ChapterEnd = this.ChapterEnd,
+ SecondsStart = this.SecondsStart,
+ SecondsEnd = this.SecondsEnd,
+ FramesStart = this.FramesStart,
+ FramesEnd = this.FramesEnd,
+ ChosenAudioTracks = new List<int>(this.ChosenAudioTracks),
+ Subtitles = this.Subtitles,
+ UseDefaultChapterNames = this.UseDefaultChapterNames,
+ OutputPath = this.OutputPath,
+ EncodingProfile = this.EncodingProfile,
+ Length = this.Length
+ };
+
+ return clone;
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Anamorphic.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Anamorphic.cs
new file mode 100644
index 000000000..b6d3d110f
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Anamorphic.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum Anamorphic
+ {
+ [Display(Name = "None")]
+ None = 0,
+ [Display(Name = "Strict")]
+ Strict,
+ [Display(Name = "Loose")]
+ Loose,
+ [Display(Name = "Custom")]
+ Custom
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs
new file mode 100644
index 000000000..159ed7c30
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum AudioEncoder
+ {
+ [Display(Name = "AAC (faac)")]
+ Faac = 0,
+
+ [Display(Name = "MP3 (lame)")]
+ Lame,
+
+ [Display(Name = "AC3 (ffmpeg)")]
+ Ac3,
+
+ [Display(Name = "Passthrough (AC3/DTS)")]
+ Passthrough,
+
+ [Display(Name = "Passthrough (AC3)")]
+ Ac3Passthrough,
+
+ [Display(Name = "Passthrough (DTS)")]
+ DtsPassthrough,
+
+ [Display(Name = "Vorbis (vorbis)")]
+ Vorbis
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoding.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoding.cs
new file mode 100644
index 000000000..0821749b5
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoding.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class AudioEncoding
+ {
+ public int InputNumber { get; set; }
+ public AudioEncoder Encoder { get; set; }
+
+ /// <summary>
+ /// Gets or sets the bitrate (in kbps) of this track.
+ /// </summary>
+ public int Bitrate { get; set; }
+ public Mixdown Mixdown { get; set; }
+
+ /// <summary>
+ /// Obsolete. Use SampleRateRaw instead.
+ /// </summary>
+ [Obsolete("This property is ignored and only exists for backwards compatibility. Use SampleRateRaw instead.")]
+ public string SampleRate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the sample rate in Hz.
+ /// </summary>
+ public int SampleRateRaw { get; set; }
+
+ public int Gain { get; set; }
+ public double Drc { get; set; }
+ public string Name { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Decomb.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Decomb.cs
new file mode 100644
index 000000000..5fa9bda74
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Decomb.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum Decomb
+ {
+ Off = 0,
+ Default,
+ Custom
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Deinterlace.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Deinterlace.cs
new file mode 100644
index 000000000..ee08ba10d
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Deinterlace.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum Deinterlace
+ {
+ Off = 0,
+ Fast,
+ Slow,
+ Slower,
+ Custom
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Denoise.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Denoise.cs
new file mode 100644
index 000000000..7b59ae1b8
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Denoise.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum Denoise
+ {
+ Off = 0,
+ Weak,
+ Medium,
+ Strong,
+ Custom
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Detelecine.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Detelecine.cs
new file mode 100644
index 000000000..fe9e543c4
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Detelecine.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum Detelecine
+ {
+ Off = 0,
+ Default,
+ Custom
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/EncodingProfile.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/EncodingProfile.cs
new file mode 100644
index 000000000..d4275b4d2
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/EncodingProfile.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class EncodingProfile
+ {
+ public EncodingProfile()
+ {
+ this.Cropping = new Cropping();
+ }
+
+ public OutputFormat OutputFormat { get; set; }
+ public OutputExtension PreferredExtension { get; set; }
+ public bool IncludeChapterMarkers { get; set; }
+ public bool LargeFile { get; set; }
+ public bool Optimize { get; set; }
+ public bool IPod5GSupport { get; set; }
+
+ public int Width { get; set; }
+ public int Height { get; set; }
+ public int MaxWidth { get; set; }
+ public int MaxHeight { get; set; }
+ public bool CustomCropping { get; set; }
+ public Cropping Cropping { get; set; }
+ public Anamorphic Anamorphic { get; set; }
+ public bool UseDisplayWidth { get; set; }
+ public int DisplayWidth { get; set; }
+ public bool KeepDisplayAspect { get; set; }
+ public int PixelAspectX { get; set; }
+ public int PixelAspectY { get; set; }
+ public int Modulus { get; set; }
+
+ public Deinterlace Deinterlace { get; set; }
+ public string CustomDeinterlace { get; set; }
+ public Decomb Decomb { get; set; }
+ public string CustomDecomb { get; set; }
+ public Detelecine Detelecine { get; set; }
+ public string CustomDetelecine { get; set; }
+ public Denoise Denoise { get; set; }
+ public string CustomDenoise { get; set; }
+ public int Deblock { get; set; }
+ public bool Grayscale { get; set; }
+
+ public VideoEncoder VideoEncoder { get; set; }
+ public string X264Options { get; set; }
+ public VideoEncodeRateType VideoEncodeRateType { get; set; }
+ public double Quality { get; set; }
+ public int TargetSize { get; set; }
+ public int VideoBitrate { get; set; }
+ public bool TwoPass { get; set; }
+ public bool TurboFirstPass { get; set; }
+ public double Framerate { get; set; }
+ public bool PeakFramerate { get; set; }
+
+ public List<AudioEncoding> AudioEncodings { get; set; }
+
+ public EncodingProfile Clone()
+ {
+ EncodingProfile profile = new EncodingProfile
+ {
+ OutputFormat = this.OutputFormat,
+ PreferredExtension = this.PreferredExtension,
+ IncludeChapterMarkers = this.IncludeChapterMarkers,
+ LargeFile = this.LargeFile,
+ Optimize = this.Optimize,
+ IPod5GSupport = this.IPod5GSupport,
+
+ Width = this.Width,
+ Height = this.Height,
+ MaxWidth = this.MaxWidth,
+ MaxHeight = this.MaxHeight,
+ CustomCropping = this.CustomCropping,
+ Cropping = this.Cropping.Clone(),
+ Anamorphic = this.Anamorphic,
+ UseDisplayWidth = this.UseDisplayWidth,
+ DisplayWidth = this.DisplayWidth,
+ KeepDisplayAspect = this.KeepDisplayAspect,
+ PixelAspectX = this.PixelAspectX,
+ PixelAspectY = this.PixelAspectY,
+ Modulus = this.Modulus,
+
+ Deinterlace = this.Deinterlace,
+ CustomDeinterlace = this.CustomDeinterlace,
+ Decomb = this.Decomb,
+ CustomDecomb = this.CustomDecomb,
+ Detelecine = this.Detelecine,
+ CustomDetelecine = this.CustomDetelecine,
+ Denoise = this.Denoise,
+ CustomDenoise = this.CustomDenoise,
+ Deblock = this.Deblock,
+ Grayscale = this.Grayscale,
+
+ VideoEncoder = this.VideoEncoder,
+ X264Options = this.X264Options,
+ VideoEncodeRateType = this.VideoEncodeRateType,
+ Quality = this.Quality,
+ TargetSize = this.TargetSize,
+ VideoBitrate = this.VideoBitrate,
+ TwoPass = this.TwoPass,
+ TurboFirstPass = this.TurboFirstPass,
+ Framerate = this.Framerate,
+ PeakFramerate = this.PeakFramerate,
+
+ AudioEncodings = new List<AudioEncoding>(this.AudioEncodings)
+ };
+
+ return profile;
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Mixdown.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Mixdown.cs
new file mode 100644
index 000000000..838c7066b
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/Mixdown.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum Mixdown
+ {
+ [Display(Name = "Dolby Pro Logic II")]
+ DolbyProLogicII = 0,
+
+ [Display(Name = "Auto")]
+ Auto,
+
+ [Display(Name = "Mono")]
+ Mono,
+
+ [Display(Name = "Stereo")]
+ Stereo,
+
+ [Display(Name = "Dolby Surround")]
+ DolbySurround,
+
+ [Display(Name = "6 Channel Discrete")]
+ SixChannelDiscrete
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputExtension.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputExtension.cs
new file mode 100644
index 000000000..cd82aab2e
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputExtension.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum OutputExtension
+ {
+ Mp4,
+ M4v
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputFormat.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputFormat.cs
new file mode 100644
index 000000000..f842fe474
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/OutputFormat.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.ComponentModel;
+
+namespace HandBrake.Interop
+{
+ public enum OutputFormat
+ {
+ [Display(Name = "MP4")]
+ Mp4,
+ [Display(Name = "MKV")]
+ Mkv
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncodeRateType.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncodeRateType.cs
new file mode 100644
index 000000000..ae08402d4
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncodeRateType.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum VideoEncodeRateType
+ {
+ TargetSize = 0,
+ AverageBitrate,
+ ConstantQuality
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs
new file mode 100644
index 000000000..923f446e1
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public enum VideoEncoder
+ {
+ [Display(Name = "H.264 (x264)")]
+ X264 = 0,
+
+ [Display(Name = "MPEG-4 (FFMpeg)")]
+ FFMpeg,
+
+ [Display(Name = "VP3 (Theora)")]
+ Theora
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Limits.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Limits.cs
new file mode 100644
index 000000000..9fdc373f5
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Limits.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class Limits
+ {
+ public int Low { get; set; }
+
+ public int High { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Size.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Size.cs
new file mode 100644
index 000000000..3f9736c86
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Size.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class Size
+ {
+ public Size(int width, int height)
+ {
+ this.Width = width;
+ this.Height = height;
+ }
+
+ public int Width { get; set; }
+ public int Height { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceSubtitle.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceSubtitle.cs
new file mode 100644
index 000000000..e07811cc8
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceSubtitle.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class SourceSubtitle
+ {
+ /// <summary>
+ /// Gets or sets the 1-based subtitle track number. 0 means foreign audio search.
+ /// </summary>
+ public int TrackNumber { get; set; }
+ public bool Default { get; set; }
+ public bool Forced { get; set; }
+ public bool BurnedIn { get; set; }
+
+ public SourceSubtitle Clone()
+ {
+ return new SourceSubtitle
+ {
+ TrackNumber = this.TrackNumber,
+ Default = this.Default,
+ Forced = this.Forced,
+ BurnedIn = this.BurnedIn
+ };
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceType.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceType.cs
new file mode 100644
index 000000000..f0a227cad
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SourceType.cs
@@ -0,0 +1,10 @@
+namespace HandBrake.Interop
+{
+ public enum SourceType
+ {
+ None = 0,
+ File,
+ VideoFolder,
+ Dvd
+ }
+} \ No newline at end of file
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SrtSubtitle.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SrtSubtitle.cs
new file mode 100644
index 000000000..1d80e1f0b
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/SrtSubtitle.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class SrtSubtitle
+ {
+ public bool Default { get; set; }
+ public string FileName { get; set; }
+ public string LanguageCode { get; set; }
+ public string CharacterCode { get; set; }
+ public int Offset { get; set; }
+
+ public SrtSubtitle Clone()
+ {
+ return new SrtSubtitle
+ {
+ Default = this.Default,
+ FileName = this.FileName,
+ LanguageCode = this.LanguageCode,
+ CharacterCode = this.CharacterCode,
+ Offset = this.Offset
+ };
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Subtitles.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Subtitles.cs
new file mode 100644
index 000000000..a9c1750e0
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Subtitles.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class Subtitles
+ {
+ public List<SrtSubtitle> SrtSubtitles { get; set; }
+ public List<SourceSubtitle> SourceSubtitles { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/VideoRangeType.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/VideoRangeType.cs
new file mode 100644
index 000000000..d0e967fbc
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/VideoRangeType.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.DataAnnotations;
+
+namespace HandBrake.Interop
+{
+ public enum VideoRangeType
+ {
+ [Display(Name = "Chapters")]
+ Chapters,
+
+ [Display(Name = "Seconds")]
+ Seconds,
+
+ [Display(Name = "Frames")]
+ Frames
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/NativeList.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/NativeList.cs
new file mode 100644
index 000000000..6d39bb8f4
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/NativeList.cs
@@ -0,0 +1,34 @@
+namespace HandBrake.Interop
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// Represents a HandBrake style native list.
+ /// </summary>
+ public class NativeList
+ {
+ /// <summary>
+ /// The list of native memory locations allocated for this list.
+ /// </summary>
+ private List<IntPtr> allocatedMemory = new List<IntPtr>();
+
+ /// <summary>
+ /// Gets or sets the pointer to the native list.
+ /// </summary>
+ public IntPtr ListPtr { get; set; }
+
+ /// <summary>
+ /// Gets the list of native memory locations allocated for this list.
+ /// </summary>
+ public List<IntPtr> AllocatedMemory
+ {
+ get
+ {
+ return allocatedMemory;
+ }
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..7e74d7e2a
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HandBrakeInterop")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("HandBrake Team")]
+[assembly: AssemblyProduct("HandBrake.Interop")]
+[assembly: AssemblyCopyright("Copyright © HandBrake Team 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("cc59844b-9e1b-4854-8b92-3b24c646aee5")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.18.0.0")]
+[assembly: AssemblyFileVersion("1.18.0.0")]
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/ScanProgressEventArgs.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/ScanProgressEventArgs.cs
new file mode 100644
index 000000000..4177ff1b7
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/ScanProgressEventArgs.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public class ScanProgressEventArgs : EventArgs
+ {
+ public int CurrentTitle { get; set; }
+ public int Titles { get; set; }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs
new file mode 100644
index 000000000..ee5f8133d
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.SourceData
+{
+ // Only contains 2 real codecs at the moment as those are what we care about. More will be added later.
+ public enum AudioCodec
+ {
+ Ac3,
+
+ Dts,
+
+ Other
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioTrack.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioTrack.cs
new file mode 100644
index 000000000..a7b7926c1
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioTrack.cs
@@ -0,0 +1,90 @@
+/* AudioTrack.cs $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+
+namespace HandBrake.SourceData
+{
+ /// <summary>
+ /// An object represending an AudioTrack associated with a Title, in a DVD
+ /// </summary>
+ public class AudioTrack
+ {
+ /// <summary>
+ /// The track number of this Audio Track
+ /// </summary>
+ public int TrackNumber { get; set; }
+
+ /// <summary>
+ /// Gets or sets the audio codec of this Track.
+ /// </summary>
+ public AudioCodec Codec { get; set; }
+
+ /// <summary>
+ /// The language (if detected) of this Audio Track
+ /// </summary>
+ public string Language { get; set; }
+
+ public string LanguageCode { get; set; }
+
+ public string Description { get; set; }
+
+ /// <summary>
+ /// Gets or sets the channel layout of this Audio Track.
+ /// </summary>
+ public int ChannelLayout { get; set; }
+
+ /// <summary>
+ /// The frequency (in Hz) of this Audio Track
+ /// </summary>
+ public int SampleRate { get; set; }
+
+ /// <summary>
+ /// The bitrate (in bits/sec) of this Audio Track.
+ /// </summary>
+ public int Bitrate { get; set; }
+
+ public string Display
+ {
+ get
+ {
+ return this.GetDisplayString(true);
+ }
+ }
+
+ public string NoTrackDisplay
+ {
+ get
+ {
+ return this.GetDisplayString(false);
+ }
+ }
+
+ /// <summary>
+ /// Override of the ToString method to make this object easier to use in the UI
+ /// </summary>
+ /// <returns>A string formatted as: {track #} {language} ({format}) ({sub-format})</returns>
+ public override string ToString()
+ {
+ return this.GetDisplayString(true);
+ }
+
+ private string GetDisplayString(bool includeTrackNumber)
+ {
+ if (includeTrackNumber)
+ {
+ return this.TrackNumber + " " + this.Description;
+ }
+ else
+ {
+ return this.Description;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Chapter.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Chapter.cs
new file mode 100644
index 000000000..74d3703e0
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Chapter.cs
@@ -0,0 +1,38 @@
+/* Chapter.cs $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+
+namespace HandBrake.SourceData
+{
+ /// <summary>
+ /// An object representing a Chapter aosciated with a Title, in a DVD
+ /// </summary>
+ public class Chapter
+ {
+ /// <summary>
+ /// The number of this Chapter, in regards to its parent Title
+ /// </summary>
+ public int ChapterNumber { get; set; }
+
+ /// <summary>
+ /// The length in time this Chapter spans
+ /// </summary>
+ public TimeSpan Duration { get; set; }
+
+ /// <summary>
+ /// Override of the ToString method to make this object easier to use in the UI
+ /// </summary>
+ /// <returns>A string formatted as: {chapter #}</returns>
+ public override string ToString()
+ {
+ return this.ChapterNumber.ToString();
+ }
+ }
+} \ No newline at end of file
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/InputType.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/InputType.cs
new file mode 100644
index 000000000..b96b4f174
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/InputType.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.DataAnnotations;
+
+namespace HandBrake.SourceData
+{
+ public enum InputType
+ {
+ [Display(Name = "File")]
+ Stream,
+
+ [Display(Name = "DVD")]
+ Dvd,
+
+ [Display(Name = "Blu-ray")]
+ Bluray
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Subtitle.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Subtitle.cs
new file mode 100644
index 000000000..5f100db30
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Subtitle.cs
@@ -0,0 +1,54 @@
+/* Subtitle.cs $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+
+namespace HandBrake.SourceData
+{
+ /// <summary>
+ /// An object that represents a subtitle associated with a Title, in a DVD
+ /// </summary>
+ public class Subtitle
+ {
+ /// <summary>
+ /// The track number of this Subtitle
+ /// </summary>
+ public int TrackNumber { get; set; }
+
+ /// <summary>
+ /// The language (if detected) of this Subtitle
+ /// </summary>
+ public string Language { get; set; }
+
+ /// <summary>
+ /// Langauage Code
+ /// </summary>
+ public string LanguageCode { get; set; }
+
+ public SubtitleType SubtitleType { get; set; }
+
+ public SubtitleSource SubtitleSource { get; set; }
+
+ /// <summary>
+ /// Override of the ToString method to make this object easier to use in the UI
+ /// </summary>
+ /// <returns>A string formatted as: {track #} {language}</returns>
+ public override string ToString()
+ {
+ return string.Format("{0} {1} ({2})", this.TrackNumber, this.Language, this.SubtitleSource);
+ }
+
+ public string Display
+ {
+ get
+ {
+ return this.ToString();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleSource.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleSource.cs
new file mode 100644
index 000000000..b884b8a32
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleSource.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.SourceData
+{
+ public enum SubtitleSource
+ {
+ VobSub,
+ SRT,
+ CC608,
+ CC708,
+ UTF8,
+ TX3G,
+ SSA
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleType.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleType.cs
new file mode 100644
index 000000000..2c4471e99
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/SubtitleType.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.SourceData
+{
+ public enum SubtitleType
+ {
+ Picture,
+ Text
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Title.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Title.cs
new file mode 100644
index 000000000..c8b296825
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/Title.cs
@@ -0,0 +1,144 @@
+/* Title.cs $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text.RegularExpressions;
+using HandBrake.Interop;
+
+namespace HandBrake.SourceData
+{
+ /// <summary>
+ /// An object that represents a single Title of a DVD
+ /// </summary>
+ public class Title
+ {
+ private static readonly CultureInfo Culture = new CultureInfo("en-US", false);
+ private readonly List<AudioTrack> audioTracks;
+ private readonly List<Chapter> chapters;
+ private readonly List<Subtitle> subtitles;
+
+ /// <summary>
+ /// The constructor for this object
+ /// </summary>
+ public Title()
+ {
+ this.audioTracks = new List<AudioTrack>();
+ this.chapters = new List<Chapter>();
+ this.subtitles = new List<Subtitle>();
+ }
+
+ /// <summary>
+ /// Gets or sets the input type of this title.
+ /// </summary>
+ public InputType InputType { get; set; }
+
+ /// <summary>
+ /// Collection of chapters in this Title
+ /// </summary>
+ public List<Chapter> Chapters
+ {
+ get { return this.chapters; }
+ }
+
+ /// <summary>
+ /// Collection of audio tracks associated with this Title
+ /// </summary>
+ public List<AudioTrack> AudioTracks
+ {
+ get { return this.audioTracks; }
+ }
+
+ /// <summary>
+ /// Collection of subtitles associated with this Title
+ /// </summary>
+ public List<Subtitle> Subtitles
+ {
+ get { return this.subtitles; }
+ }
+
+ /// <summary>
+ /// The track number of this Title (1-based).
+ /// </summary>
+ public int TitleNumber { get; set; }
+
+ /// <summary>
+ /// The length in time of this Title
+ /// </summary>
+ public TimeSpan Duration { get; set; }
+
+ /// <summary>
+ /// The resolution (width/height) of this Title
+ /// </summary>
+ public Size Resolution { get; set; }
+
+ /// <summary>
+ /// The aspect ratio of this Title
+ /// </summary>
+ public double AspectRatio { get; set; }
+
+ /// <summary>
+ /// Gets or sets the number of angles on the title.
+ /// </summary>
+ public int AngleCount { get; set; }
+
+ /// <summary>
+ /// Par Value
+ /// </summary>
+ public Size ParVal { get; set; }
+
+ /// <summary>
+ /// The automatically detected crop region for this Title.
+ /// This is an int array with 4 items in it as so:
+ /// 0:
+ /// 1:
+ /// 2:
+ /// 3:
+ /// </summary>
+ public Cropping AutoCropDimensions { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of the video codec for this title.
+ /// </summary>
+ public string VideoCodecName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the video frame rate for this title.
+ /// </summary>
+ public double Framerate { get; set; }
+
+ /// <summary>
+ /// The total number of frames in this title.
+ /// </summary>
+ public int Frames
+ {
+ get
+ {
+ return (int)Math.Ceiling(((double)this.Duration.TotalSeconds) * this.Framerate);
+ }
+ }
+
+ /// <summary>
+ /// Override of the ToString method to provide an easy way to use this object in the UI
+ /// </summary>
+ /// <returns>A string representing this track in the format: {title #} (00:00:00)</returns>
+ public override string ToString()
+ {
+ return string.Format("{0} ({1:00}:{2:00}:{3:00})", this.TitleNumber, this.Duration.Hours,
+ this.Duration.Minutes, this.Duration.Seconds);
+ }
+
+ public string Display
+ {
+ get
+ {
+ return this.ToString();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Utilities.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Utilities.cs
new file mode 100644
index 000000000..41ab39da5
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Utilities.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HandBrake.Interop
+{
+ public static class Utilities
+ {
+ public static int GreatestCommonFactor(int a, int b)
+ {
+ if (a == 0)
+ {
+ return b;
+ }
+
+ if (b == 0)
+ {
+ return a;
+ }
+
+ if (a > b)
+ {
+ return GreatestCommonFactor(a % b, b);
+ }
+ else
+ {
+ return GreatestCommonFactor(a, b % a);
+ }
+ }
+ }
+}
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/libgcc_s_sjlj-1.dll b/win/CS/HandBrake.Interop/HandBrakeInterop/libgcc_s_sjlj-1.dll
new file mode 100644
index 000000000..b86e5dfe9
--- /dev/null
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/libgcc_s_sjlj-1.dll
Binary files differ