/// <returns>An image with the requested preview.</returns>\r
public BitmapImage GetPreview(EncodeJob job, int previewNumber)\r
{\r
- hb_title_s title = this.GetOriginalTitle(job.Title);\r
+ IntPtr nativeJobPtr = HBFunctions.hb_job_init_by_index(this.hbHandle, job.Title);\r
+ var nativeJob = InteropUtilities.ReadStructure<hb_job_s>(nativeJobPtr);\r
\r
- hb_job_s nativeJob = InteropUtilities.ReadStructure<hb_job_s>(title.job);\r
List<IntPtr> allocatedMemory = this.ApplyJob(ref nativeJob, job);\r
\r
// There are some problems with getting previews with deinterlacing. Disabling for now.\r
nativeJob.deinterlace = 0;\r
\r
- // Create a new job pointer from our modified job object\r
- IntPtr newJob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_job_s)));\r
- Marshal.StructureToPtr(nativeJob, newJob, false);\r
- allocatedMemory.Add(newJob);\r
-\r
int outputWidth = nativeJob.width;\r
int outputHeight = nativeJob.height;\r
int imageBufferSize = outputWidth * outputHeight * 4;\r
IntPtr nativeBuffer = Marshal.AllocHGlobal(imageBufferSize);\r
allocatedMemory.Add(nativeBuffer);\r
- HBFunctions.hb_set_job(this.hbHandle, job.Title, ref nativeJob);\r
- HBFunctions.hb_get_preview(this.hbHandle, ref title, previewNumber, nativeBuffer);\r
+ HBFunctions.hb_get_preview(this.hbHandle, ref nativeJob, previewNumber, nativeBuffer);\r
+\r
+ // We've used the job to get the preview. Clean up the job.\r
+ InteropUtilities.CloseJob(nativeJobPtr);\r
\r
// Copy the filled image buffer to a managed array.\r
byte[] managedBuffer = new byte[imageBufferSize];\r
Marshal.Copy(nativeBuffer, managedBuffer, 0, imageBufferSize);\r
\r
+ // We've copied the data out of unmanaged memory. Clean up that memory now.\r
InteropUtilities.FreeMemory(allocatedMemory);\r
\r
var bitmap = new System.Drawing.Bitmap(outputWidth, outputHeight);\r
/// for calculating bitrate when the target size would be wrong.</param>\r
public void StartEncode(EncodeJob job, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds)\r
{\r
+ EncodingProfile profile = job.EncodingProfile;\r
this.currentJob = job;\r
- hb_job_s nativeJob = InteropUtilities.ReadStructure<hb_job_s>(this.GetOriginalTitle(job.Title).job);\r
+\r
+ IntPtr nativeJobPtr = HBFunctions.hb_job_init_by_index(this.hbHandle, job.Title);\r
+ var nativeJob = InteropUtilities.ReadStructure<hb_job_s>(nativeJobPtr);\r
+\r
+ //hb_job_s nativeJob = InteropUtilities.ReadStructure<hb_job_s>(this.GetOriginalTitle(job.Title).job);\r
this.encodeAllocatedMemory = this.ApplyJob(ref nativeJob, job, preview, previewNumber, previewSeconds, overallSelectedLengthSeconds);\r
\r
- if (!preview && job.EncodingProfile.IncludeChapterMarkers)\r
+ if (!preview && profile.IncludeChapterMarkers)\r
{\r
Title title = this.GetTitle(job.Title);\r
int numChapters = title.Chapters.Count;\r
}\r
}\r
\r
- string x264Options = job.EncodingProfile.X264Options ?? string.Empty;\r
+ string x264Options = profile.X264Options ?? string.Empty;\r
IntPtr originalX264Options = Marshal.StringToHGlobalAnsi(x264Options);\r
this.encodeAllocatedMemory.Add(originalX264Options);\r
\r
- if (!string.IsNullOrEmpty(job.EncodingProfile.X264Profile))\r
+ if (!string.IsNullOrEmpty(profile.X264Profile))\r
{\r
- nativeJob.x264_profile = Marshal.StringToHGlobalAnsi(job.EncodingProfile.X264Profile);\r
+ nativeJob.x264_profile = Marshal.StringToHGlobalAnsi(profile.X264Profile);\r
this.encodeAllocatedMemory.Add(nativeJob.x264_profile);\r
}\r
\r
- if (!string.IsNullOrEmpty(job.EncodingProfile.X264Preset))\r
+ if (!string.IsNullOrEmpty(profile.X264Preset))\r
{\r
- nativeJob.x264_preset = Marshal.StringToHGlobalAnsi(job.EncodingProfile.X264Preset);\r
+ nativeJob.x264_preset = Marshal.StringToHGlobalAnsi(profile.X264Preset);\r
this.encodeAllocatedMemory.Add(nativeJob.x264_preset);\r
}\r
\r
- if (!string.IsNullOrEmpty(job.EncodingProfile.X264Tune))\r
+ if (profile.X264Tunes != null && profile.X264Tunes.Count > 0)\r
{\r
- nativeJob.x264_tune = Marshal.StringToHGlobalAnsi(job.EncodingProfile.X264Tune);\r
+ nativeJob.x264_tune = Marshal.StringToHGlobalAnsi(string.Join(",", profile.X264Tunes));\r
this.encodeAllocatedMemory.Add(nativeJob.x264_tune);\r
}\r
\r
\r
HBFunctions.hb_start(this.hbHandle);\r
\r
+ // Should be safe to clean up the job we started with; a copy is in the queue now.\r
+ InteropUtilities.CloseJob(nativeJobPtr);\r
+\r
this.encodePollTimer = new System.Timers.Timer();\r
this.encodePollTimer.Interval = EncodePollIntervalMs;\r
\r
/// <param name="parHeight">The pixel aspect Y number.</param>\r
public void GetSize(EncodeJob job, out int width, out int height, out int parWidth, out int parHeight)\r
{\r
+ Title title = this.GetTitle(job.Title);\r
+\r
if (job.EncodingProfile.Anamorphic == Anamorphic.None)\r
{\r
- Title title = this.GetTitle(job.Title);\r
Size storageDimensions = CalculateNonAnamorphicOutput(job.EncodingProfile, title);\r
\r
width = storageDimensions.Width;\r
return;\r
}\r
\r
- var nativeJob = InteropUtilities.ReadStructure<hb_job_s>(this.GetOriginalTitle(job.Title).job);\r
- List<IntPtr> allocatedMemory = this.ApplyJob(ref nativeJob, job);\r
+ IntPtr nativeJobPtr = HBFunctions.hb_job_init_by_index(this.hbHandle, job.Title);\r
+ var nativeJob = InteropUtilities.ReadStructure<hb_job_s>(nativeJobPtr);\r
\r
- int refWidth = 0;\r
- int refHeight = 0;\r
- int refParWidth = 0;\r
- int refParHeight = 0;\r
- HBFunctions.hb_set_anamorphic_size(ref nativeJob, ref refWidth, ref refHeight, ref refParWidth, ref refParHeight);\r
+ List<IntPtr> allocatedMemory = this.ApplyJob(ref nativeJob, job);\r
InteropUtilities.FreeMemory(allocatedMemory);\r
\r
- width = refWidth;\r
- height = refHeight;\r
- parWidth = refParWidth;\r
- parHeight = refParHeight;\r
+ InteropUtilities.CloseJob(nativeJobPtr);\r
+\r
+ // During the ApplyJob call, it modified nativeJob to have the correct width, height and PAR.\r
+ // We use those for the size.\r
+ width = nativeJob.width;\r
+ height = nativeJob.height;\r
+ parWidth = nativeJob.anamorphic.par_width;\r
+ parHeight = nativeJob.anamorphic.par_height;\r
}\r
\r
+\r
+\r
/// <summary>\r
/// Frees any resources associated with this object.\r
/// </summary>\r
int height = profile.Height;\r
\r
Cropping crop;\r
- if (profile.CustomCropping)\r
- {\r
- crop = profile.Cropping;\r
- }\r
- else\r
+ switch (profile.CroppingType)\r
{\r
- crop = title.AutoCropDimensions;\r
+ case CroppingType.Automatic:\r
+ crop = title.AutoCropDimensions;\r
+ break;\r
+ case CroppingType.Custom:\r
+ crop = profile.Cropping;\r
+ break;\r
+ default:\r
+ crop = new Cropping();\r
+ break;\r
}\r
\r
sourceWidth -= crop.Left;\r
{\r
this.titles = new List<Title>();\r
\r
- IntPtr listPtr = HBFunctions.hb_get_titles(this.hbHandle);\r
- this.originalTitles = InteropUtilities.ConvertList<hb_title_s>(listPtr);\r
+ IntPtr titleSetPtr = HBFunctions.hb_get_title_set(this.hbHandle);\r
+ hb_title_set_s titleSet = InteropUtilities.ReadStructure<hb_title_set_s>(titleSetPtr);\r
+ this.originalTitles = InteropUtilities.ConvertList<hb_title_s>(titleSet.list_title);\r
\r
foreach (hb_title_s title in this.originalTitles)\r
{\r
\r
if (this.originalTitles.Count > 0)\r
{\r
- var nativeJob = InteropUtilities.ReadStructure<hb_job_s>(this.originalTitles[0].job);\r
- this.featureTitle = nativeJob.feature;\r
+ this.featureTitle = titleSet.feature;\r
}\r
else\r
{\r
\r
nativeJob.chapter_markers = profile.IncludeChapterMarkers ? 1 : 0;\r
\r
- Cropping crop;\r
-\r
- if (profile.CustomCropping)\r
- {\r
- crop = profile.Cropping;\r
- }\r
- else\r
- {\r
- crop = title.AutoCropDimensions;\r
- }\r
+ Cropping crop = GetCropping(profile, title);\r
\r
nativeJob.crop[0] = crop.Top;\r
nativeJob.crop[1] = crop.Bottom;\r
break;\r
case Anamorphic.Strict:\r
nativeJob.anamorphic.mode = 1;\r
+\r
+ nativeJob.anamorphic.par_width = title.ParVal.Width;\r
+ nativeJob.anamorphic.par_height = title.ParVal.Height;\r
break;\r
case Anamorphic.Loose:\r
nativeJob.anamorphic.mode = 2;\r
\r
nativeJob.maxWidth = profile.MaxWidth;\r
\r
+ nativeJob.anamorphic.par_width = title.ParVal.Width;\r
+ nativeJob.anamorphic.par_height = title.ParVal.Height;\r
break;\r
case Anamorphic.Custom:\r
nativeJob.anamorphic.mode = 3;\r
\r
return newTitle;\r
}\r
+\r
+ /// <summary>\r
+ /// Gets the cropping to use for the given encoding profile and title.\r
+ /// </summary>\r
+ /// <param name="profile">The encoding profile to use.</param>\r
+ /// <param name="title">The title being encoded.</param>\r
+ /// <returns>The cropping to use for the encode.</returns>\r
+ private static Cropping GetCropping(EncodingProfile profile, Title title)\r
+ {\r
+ Cropping crop;\r
+ switch (profile.CroppingType)\r
+ {\r
+ case CroppingType.Automatic:\r
+ crop = title.AutoCropDimensions;\r
+ break;\r
+ case CroppingType.Custom:\r
+ crop = profile.Cropping;\r
+ break;\r
+ default:\r
+ crop = new Cropping();\r
+ break;\r
+ }\r
+ return crop;\r
+ }\r
}\r
}\r
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]\r
public struct hb_metadata_s\r
{\r
- /// char[255]\r
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
public string name;\r
\r
- /// char[255]\r
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
public string artist;\r
\r
- /// char[255]\r
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
public string composer;\r
\r
- /// char[255]\r
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
public string release_date;\r
\r
- /// char[1024]\r
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
public string comment;\r
\r
- /// char[255]\r
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
public string album;\r
\r
- /// char[255]\r
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
+ public string album_artist;\r
+\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
public string genre;\r
\r
- /// uint32_t->unsigned int\r
- public uint coverart_size;\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
+ public string description;\r
+\r
+ /// char *\r
+ [MarshalAs(UnmanagedType.LPStr)]\r
+ public string long_description;\r
\r
/// uint8_t*\r
- public IntPtr coverart;\r
+ public IntPtr list_coverart;\r
}\r
\r
[StructLayout(LayoutKind.Sequential)]\r
public uint x;\r
}\r
\r
- [StructLayout(LayoutKind.Sequential)]\r
- public struct hb_title_set_s\r
- {\r
- ///hb_list_t *\r
- public hb_list_s list_title;\r
-\r
- // int\r
- public int feature;\r
- }\r
-\r
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]\r
public delegate void LoggingCallback(string message);\r
}\r
public int Height { get; set; }\r
public int MaxWidth { get; set; }\r
public int MaxHeight { get; set; }\r
- public bool CustomCropping { get; set; }\r
+ public CroppingType CroppingType { get; set; }\r
public Cropping Cropping { get; set; }\r
public Anamorphic Anamorphic { get; set; }\r
public bool UseDisplayWidth { get; set; }\r
public string X264Options { get; set; }\r
public string X264Profile { get; set; }\r
public string X264Preset { get; set; }\r
- public string X264Tune { get; set; }\r
+\r
+ public List<string> X264Tunes { get; set; }\r
public string H264Level { get; set; }\r
public VideoEncodeRateType VideoEncodeRateType { get; set; }\r
public double Quality { get; set; }\r
public double Framerate { get; set; }\r
public bool ConstantFramerate { get; set; }\r
\r
- [Obsolete("This setting is obsolete. Use Framerate and ConstantFramerate instead.")]\r
- public bool PeakFramerate { get; set; }\r
-\r
public List<AudioEncoding> AudioEncodings { get; set; }\r
public string AudioEncoderFallback { get; set; }\r
\r
public EncodingProfile Clone()\r
{\r
- EncodingProfile profile = new EncodingProfile\r
+ var profile = new EncodingProfile\r
{\r
OutputFormat = this.OutputFormat,\r
PreferredExtension = this.PreferredExtension,\r
Height = this.Height,\r
MaxWidth = this.MaxWidth,\r
MaxHeight = this.MaxHeight,\r
- CustomCropping = this.CustomCropping,\r
+ CroppingType = this.CroppingType,\r
Cropping = this.Cropping.Clone(),\r
Anamorphic = this.Anamorphic,\r
UseDisplayWidth = this.UseDisplayWidth,\r
X264Options = this.X264Options,\r
X264Profile = this.X264Profile,\r
X264Preset = this.X264Preset,\r
- X264Tune = this.X264Tune,\r
+ X264Tunes = this.X264Tunes,\r
H264Level = this.H264Level,\r
VideoEncodeRateType = this.VideoEncodeRateType,\r
Quality = this.Quality,\r
TurboFirstPass = this.TurboFirstPass,\r
Framerate = this.Framerate,\r
ConstantFramerate = this.ConstantFramerate,\r
-#pragma warning disable 612,618\r
- PeakFramerate = this.PeakFramerate,\r
-#pragma warning restore 612,618\r
\r
AudioEncodings = new List<AudioEncoding>(this.AudioEncodings)\r
};\r