using System.Diagnostics;\r
using System.Drawing;\r
using System.Drawing.Imaging;\r
- using System.Globalization;\r
using System.IO;\r
using System.Linq;\r
using System.Runtime.ExceptionServices;\r
using System.Runtime.InteropServices;\r
- using System.Text;\r
using System.Timers;\r
using System.Windows.Media.Imaging;\r
\r
\r
using Newtonsoft.Json;\r
\r
- using Size = HandBrake.Interop.Model.Size;\r
+ using Geometry = HandBrake.Interop.Json.Anamorphic.Geometry;\r
\r
/// <summary>\r
/// A wrapper for a HandBrake instance.\r
/// </summary>\r
private IntPtr hbHandle;\r
\r
- /// <summary>\r
- /// The number of previews created during scan.\r
- /// </summary>\r
- private int previewCount;\r
-\r
/// <summary>\r
/// The timer to poll for scan status.\r
/// </summary>\r
/// </summary>\r
private bool disposed;\r
\r
- /// <summary>\r
- /// The last scan.\r
- /// </summary>\r
- private JsonScanObject lastScan;\r
-\r
/// <summary>\r
/// Finalizes an instance of the HandBrakeInstance class.\r
/// </summary>\r
}\r
}\r
\r
- /// <summary>\r
- /// Gets the number of previews created during scan.\r
- /// </summary>\r
- public int PreviewCount\r
- {\r
- get\r
- {\r
- return this.previewCount;\r
- }\r
- }\r
-\r
/// <summary>\r
/// Gets the index of the default title.\r
/// </summary>\r
/// <summary>\r
/// Initializes this instance.\r
/// </summary>\r
- /// <param name="verbosity">The code for the logging verbosity to use.</param>\r
+ /// <param name="verbosity">\r
+ /// The code for the logging verbosity to use.\r
+ /// </param>\r
public void Initialize(int verbosity)\r
{\r
HandBrakeUtils.EnsureGlobalInit();\r
/// <summary>\r
/// Starts scanning the given path.\r
/// </summary>\r
- /// <param name="path">The path to the video to scan.</param>\r
- /// <param name="previewCount">The number of preview images to make.</param>\r
- /// <param name="minDuration">The minimum duration of a title to show up on the scan.</param>\r
+ /// <param name="path">\r
+ /// The path to the video to scan.\r
+ /// </param>\r
+ /// <param name="previewCount">\r
+ /// The number of preview images to make.\r
+ /// </param>\r
+ /// <param name="minDuration">\r
+ /// The minimum duration of a title to show up on the scan.\r
+ /// </param>\r
public void StartScan(string path, int previewCount, TimeSpan minDuration)\r
{\r
this.StartScan(path, previewCount, minDuration, 0);\r
/// <summary>\r
/// Starts a scan for the given input path.\r
/// </summary>\r
- /// <param name="path">The path of the video to scan.</param>\r
- /// <param name="previewCount">The number of preview images to generate for each title while scanning.</param>\r
+ /// <param name="path">\r
+ /// The path of the video to scan.\r
+ /// </param>\r
+ /// <param name="previewCount">\r
+ /// The number of preview images to generate for each title while scanning.\r
+ /// </param>\r
public void StartScan(string path, int previewCount)\r
{\r
this.StartScan(path, previewCount, TimeSpan.FromSeconds(10), 0);\r
/// <summary>\r
/// Starts a scan of the given path.\r
/// </summary>\r
- /// <param name="path">The path of the video to scan.</param>\r
- /// <param name="previewCount">The number of preview images to generate for each title while scanning.</param>\r
- /// <param name="titleIndex">The title index to scan (1-based, 0 for all titles).</param>\r
+ /// <param name="path">\r
+ /// The path of the video to scan.\r
+ /// </param>\r
+ /// <param name="previewCount">\r
+ /// The number of preview images to generate for each title while scanning.\r
+ /// </param>\r
+ /// <param name="titleIndex">\r
+ /// The title index to scan (1-based, 0 for all titles).\r
+ /// </param>\r
public void StartScan(string path, int previewCount, int titleIndex)\r
{\r
this.StartScan(path, previewCount, TimeSpan.Zero, titleIndex);\r
/// <summary>\r
/// Starts a scan of the given path.\r
/// </summary>\r
- /// <param name="path">The path of the video to scan.</param>\r
- /// <param name="previewCount">The number of previews to make on each title.</param>\r
- /// <param name="minDuration">The minimum duration of a title to show up on the scan.</param>\r
- /// <param name="titleIndex">The title index to scan (1-based, 0 for all titles).</param>\r
+ /// <param name="path">\r
+ /// The path of the video to scan.\r
+ /// </param>\r
+ /// <param name="previewCount">\r
+ /// The number of previews to make on each title.\r
+ /// </param>\r
+ /// <param name="minDuration">\r
+ /// The minimum duration of a title to show up on the scan.\r
+ /// </param>\r
+ /// <param name="titleIndex">\r
+ /// The title index to scan (1-based, 0 for all titles).\r
+ /// </param>\r
public void StartScan(string path, int previewCount, TimeSpan minDuration, int titleIndex)\r
{\r
- this.previewCount = previewCount;\r
-\r
IntPtr pathPtr = InteropUtilities.ToUtf8PtrFromString(path);\r
HBFunctions.hb_scan(this.hbHandle, pathPtr, titleIndex, previewCount, 1, (ulong)(minDuration.TotalSeconds * 90000));\r
Marshal.FreeHGlobal(pathPtr);\r
/// <remarks>\r
/// Only incorporates sizing and aspect ratio into preview image.\r
/// </remarks>\r
- /// <param name="job">The encode job to preview.</param>\r
- /// <param name="previewNumber">The index of the preview to get (0-based).</param>\r
- /// <returns>An image with the requested preview.</returns>\r
+ /// <param name="job">\r
+ /// The encode job to preview.\r
+ /// </param>\r
+ /// <param name="previewNumber">\r
+ /// The index of the preview to get (0-based).\r
+ /// </param>\r
+ /// <returns>\r
+ /// An image with the requested preview.\r
+ /// </returns>\r
[HandleProcessCorruptedStateExceptions] \r
public BitmapImage GetPreview(EncodeJob job, int previewNumber)\r
{\r
// Creat the Expected Output Geometry details for libhb.\r
hb_geometry_settings_s uiGeometry = new hb_geometry_settings_s\r
{\r
- crop = new[] { job.EncodingProfile.Cropping.Top, job.EncodingProfile.Cropping.Bottom, job.EncodingProfile.Cropping.Left, job.EncodingProfile.Cropping.Right },\r
- itu_par = 0,\r
+ crop = new[] { job.EncodingProfile.Cropping.Top, job.EncodingProfile.Cropping.Bottom, job.EncodingProfile.Cropping.Left, job.EncodingProfile.Cropping.Right }, \r
+ itu_par = 0, \r
keep = (int)AnamorphicFactory.KeepSetting.HB_KEEP_WIDTH + (job.EncodingProfile.KeepDisplayAspect ? 0x04 : 0), // TODO Keep Width?\r
- maxWidth = job.EncodingProfile.MaxWidth,\r
- maxHeight = job.EncodingProfile.MaxHeight,\r
- mode = (int)(hb_anamorphic_mode_t)job.EncodingProfile.Anamorphic,\r
- modulus = job.EncodingProfile.Modulus,\r
+ maxWidth = job.EncodingProfile.MaxWidth, \r
+ maxHeight = job.EncodingProfile.MaxHeight, \r
+ mode = (int)(hb_anamorphic_mode_t)job.EncodingProfile.Anamorphic, \r
+ modulus = job.EncodingProfile.Modulus, \r
geometry = new hb_geometry_s\r
{\r
- height = job.EncodingProfile.Height,\r
- width = job.EncodingProfile.Width,\r
+ height = job.EncodingProfile.Height, \r
+ width = job.EncodingProfile.Width, \r
par = job.EncodingProfile.Anamorphic != Anamorphic.Custom\r
? new hb_rational_t { den = title.ParVal.Height, num = title.ParVal.Width }\r
: new hb_rational_t { den = job.EncodingProfile.PixelAspectY, num = job.EncodingProfile.PixelAspectX }\r
};\r
\r
// Sanatise the input.\r
- Json.Anamorphic.Geometry resultGeometry = AnamorphicFactory.CreateGeometry(job, title, AnamorphicFactory.KeepSetting.HB_KEEP_WIDTH); // TODO this keep isn't right.\r
+ Geometry resultGeometry = AnamorphicFactory.CreateGeometry(job, title, AnamorphicFactory.KeepSetting.HB_KEEP_WIDTH); // TODO this keep isn't right.\r
int width = resultGeometry.Width * resultGeometry.PAR.Num / resultGeometry.PAR.Den;\r
int height = resultGeometry.Height;\r
uiGeometry.geometry.height = resultGeometry.Height; // Prased the height now.\r
}\r
}\r
\r
- /// <summary>\r
- /// Calculates the video bitrate for the given job and target size.\r
- /// </summary>\r
- /// <param name="job">The encode job.</param>\r
- /// <param name="sizeMB">The target size in MB.</param>\r
- /// <param name="overallSelectedLengthSeconds">The currently selected encode length. Used in preview\r
- /// for calculating bitrate when the target size would be wrong.</param>\r
- /// <returns>The video bitrate in kbps.</returns>\r
- public int CalculateBitrate(EncodeJob job, int sizeMB, double overallSelectedLengthSeconds = 0)\r
- {\r
- long availableBytes = ((long)sizeMB) * 1024 * 1024;\r
-\r
- EncodingProfile profile = job.EncodingProfile;\r
- Title title = this.GetTitle(job.Title);\r
-\r
- double lengthSeconds = overallSelectedLengthSeconds > 0 ? overallSelectedLengthSeconds : HandBrakeUtils.GetJobLengthSeconds(job, title);\r
- lengthSeconds += 1.5;\r
-\r
- double outputFramerate;\r
- if (profile.Framerate == 0)\r
- {\r
- outputFramerate = title.Framerate;\r
- }\r
- else\r
- {\r
- // Not sure what to do for VFR here hb_calc_bitrate never handled it...\r
- // just use the peak for now.\r
- outputFramerate = profile.Framerate;\r
- }\r
-\r
- long frames = (long)(lengthSeconds * outputFramerate);\r
-\r
- availableBytes -= frames * HandBrakeUtils.ContainerOverheadPerFrame;\r
\r
- List<Tuple<AudioEncoding, int>> outputTrackList = this.GetOutputTracks(job, title);\r
- availableBytes -= HandBrakeUtils.GetAudioSize(job, lengthSeconds, title, outputTrackList);\r
-\r
- if (availableBytes < 0)\r
- {\r
- return 0;\r
- }\r
-\r
- // Video bitrate is in kilobits per second, or where 1 kbps is 1000 bits per second.\r
- // So 1 kbps is 125 bytes per second.\r
- return (int)(availableBytes / (125 * lengthSeconds));\r
- }\r
-\r
- /// <summary>\r
- /// Gives estimated file size (in MB) of the given job and video bitrate.\r
- /// </summary>\r
- /// <param name="job">The encode job.</param>\r
- /// <param name="videoBitrate">The video bitrate to be used (kbps).</param>\r
- /// <returns>The estimated file size (in MB) of the given job and video bitrate.</returns>\r
- public double CalculateFileSize(EncodeJob job, int videoBitrate)\r
- {\r
- long totalBytes = 0;\r
-\r
- EncodingProfile profile = job.EncodingProfile;\r
- Title title = this.GetTitle(job.Title);\r
-\r
- double lengthSeconds = HandBrakeUtils.GetJobLengthSeconds(job, title);\r
- lengthSeconds += 1.5;\r
-\r
- double outputFramerate;\r
- if (profile.Framerate == 0)\r
- {\r
- outputFramerate = title.Framerate;\r
- }\r
- else\r
- {\r
- // Not sure what to do for VFR here hb_calc_bitrate never handled it...\r
- // just use the peak for now.\r
- outputFramerate = profile.Framerate;\r
- }\r
-\r
- long frames = (long)(lengthSeconds * outputFramerate);\r
-\r
- totalBytes += (long)(lengthSeconds * videoBitrate * 125);\r
- totalBytes += frames * HandBrakeUtils.ContainerOverheadPerFrame;\r
-\r
- List<Tuple<AudioEncoding, int>> outputTrackList = this.GetOutputTracks(job, title);\r
- totalBytes += HandBrakeUtils.GetAudioSize(job, lengthSeconds, title, outputTrackList);\r
-\r
- return (double)totalBytes / 1024 / 1024;\r
- }\r
\r
/// <summary>\r
/// Starts an encode with the given job.\r
/// </param>\r
public void StartEncode(EncodeJob job, Title title, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds, int scanPreviewCount)\r
{\r
- this.previewCount = scanPreviewCount;\r
-\r
JsonEncodeObject encodeObject = EncodeFactory.Create(job, title);\r
\r
JsonSerializerSettings settings = new JsonSerializerSettings\r
HBFunctions.hb_add_json(this.hbHandle, InteropUtilities.ToUtf8PtrFromString(encode));\r
HBFunctions.hb_start(this.hbHandle);\r
\r
- this.encodePollTimer = new System.Timers.Timer();\r
+ this.encodePollTimer = new Timer();\r
this.encodePollTimer.Interval = EncodePollIntervalMs;\r
\r
this.encodePollTimer.Elapsed += (o, e) =>\r
/// <summary>\r
/// Frees any resources associated with this object.\r
/// </summary>\r
- /// <param name="disposing">True if managed objects as well as unmanaged should be disposed.</param>\r
+ /// <param name="disposing">\r
+ /// True if managed objects as well as unmanaged should be disposed.\r
+ /// </param>\r
protected virtual void Dispose(bool disposing)\r
{\r
if (disposing)\r
{\r
this.ScanProgress(this, new ScanProgressEventArgs\r
{\r
- Progress = state.Scanning.Progress,\r
- CurrentPreview = state.Scanning.Preview,\r
- Previews = state.Scanning.PreviewCount,\r
- CurrentTitle = state.Scanning.Title,\r
+ Progress = state.Scanning.Progress, \r
+ CurrentPreview = state.Scanning.Preview, \r
+ Previews = state.Scanning.PreviewCount, \r
+ CurrentTitle = state.Scanning.Title, \r
Titles = state.Scanning.TitleCount\r
});\r
}\r
string scanJson = InteropUtilities.ToStringFromUtf8Ptr(jsonMsg);\r
\r
JsonScanObject scanObject = JsonConvert.DeserializeObject<JsonScanObject>(scanJson);\r
- lastScan = scanObject;\r
\r
foreach (Title title in ScanFactory.CreateTitleSet(scanObject))\r
{ \r
{\r
var progressEventArgs = new EncodeProgressEventArgs\r
{\r
- FractionComplete = state.Working.Progress,\r
- CurrentFrameRate = state.Working.Rate,\r
- AverageFrameRate = state.Working.RateAvg,\r
- EstimatedTimeLeft = new TimeSpan(state.Working.Hours, state.Working.Minutes, state.Working.Seconds),\r
+ FractionComplete = state.Working.Progress, \r
+ CurrentFrameRate = state.Working.Rate, \r
+ AverageFrameRate = state.Working.RateAvg, \r
+ EstimatedTimeLeft = new TimeSpan(state.Working.Hours, state.Working.Minutes, state.Working.Seconds), \r
Pass = 1, // TODO\r
};\r
\r
}\r
}\r
\r
- /// <summary>\r
- /// Gets a list of encodings and target track indices (1-based).\r
- /// </summary>\r
- /// <param name="job">The encode job</param>\r
- /// <param name="title">The title the job is meant to encode.</param>\r
- /// <returns>A list of encodings and target track indices (1-based).</returns>\r
- private List<Tuple<AudioEncoding, int>> GetOutputTracks(EncodeJob job, Title title)\r
- {\r
- var list = new List<Tuple<AudioEncoding, int>>();\r
-\r
- foreach (AudioEncoding encoding in job.EncodingProfile.AudioEncodings)\r
- {\r
- if (encoding.InputNumber == 0)\r
- {\r
- // Add this encoding for all chosen tracks\r
- foreach (int chosenTrack in job.ChosenAudioTracks)\r
- {\r
- // In normal cases we'll never have a chosen audio track that doesn't exist but when batch encoding\r
- // we just choose the first audio track without checking if it exists.\r
- if (chosenTrack <= title.AudioTracks.Count)\r
- {\r
- list.Add(new Tuple<AudioEncoding, int>(encoding, chosenTrack));\r
- }\r
- }\r
- }\r
- else if (encoding.InputNumber <= job.ChosenAudioTracks.Count)\r
- {\r
- // Add this encoding for the specified track, if it exists\r
- int trackNumber = job.ChosenAudioTracks[encoding.InputNumber - 1];\r
-\r
- // In normal cases we'll never have a chosen audio track that doesn't exist but when batch encoding\r
- // we just choose the first audio track without checking if it exists.\r
- if (trackNumber <= title.AudioTracks.Count)\r
- {\r
- list.Add(new Tuple<AudioEncoding, int>(encoding, trackNumber));\r
- }\r
- }\r
- }\r
-\r
- return list;\r
- }\r
-\r
- /// <summary>\r
- /// Gets the title, given the 1-based title number.\r
- /// </summary>\r
- /// <param name="titleNumber">The number of the title (1-based).</param>\r
- /// <returns>The requested Title.</returns>\r
- private Title GetTitle(int titleNumber)\r
- {\r
- return this.Titles.SingleOrDefault(title => title.TitleNumber == titleNumber);\r
- }\r
}\r
}\r
{\r
using System;\r
using System.Collections.Generic;\r
- using System.Linq;\r
+ using System.Diagnostics;\r
using System.Runtime.InteropServices;\r
\r
using HandBrake.Interop.EventArgs;\r
using HandBrake.Interop.HbLib;\r
- using HandBrake.Interop.Json.Anamorphic;\r
- using HandBrake.Interop.Json.Scan;\r
using HandBrake.Interop.Model;\r
using HandBrake.Interop.Model.Encoding;\r
using HandBrake.Interop.Model.Scan;\r
\r
- using Newtonsoft.Json;\r
-\r
/// <summary>\r
/// HandBrake Interop Utilities\r
/// </summary>\r
/// <summary>\r
/// Enables or disables LibDVDNav. If disabled libdvdread will be used instead.\r
/// </summary>\r
- /// <param name="enableDvdNav">True to enable LibDVDNav.</param>\r
+ /// <param name="enableDvdNav">\r
+ /// True to enable LibDVDNav.\r
+ /// </param>\r
public static void SetDvdNav(bool enableDvdNav)\r
{\r
HBFunctions.hb_dvd_set_dvdnav(enableDvdNav ? 1 : 0);\r
/// <summary>\r
/// Handles log messages from HandBrake.\r
/// </summary>\r
- /// <param name="message">The log message (including newline).</param>\r
+ /// <param name="message">\r
+ /// The log message (including newline).\r
+ /// </param>\r
public static void LoggingHandler(string message)\r
{\r
if (!string.IsNullOrEmpty(message))\r
/// <summary>\r
/// Handles errors from HandBrake.\r
/// </summary>\r
- /// <param name="message">The error message.</param>\r
+ /// <param name="message">\r
+ /// The error message.\r
+ /// </param>\r
public static void ErrorHandler(string message)\r
{\r
if (!string.IsNullOrEmpty(message))\r
/// <summary>\r
/// Checks to see if the given H.264 level is valid given the inputs.\r
/// </summary>\r
- /// <param name="level">The level to check.</param>\r
- /// <param name="width">The output picture width.</param>\r
- /// <param name="height">The output picture height.</param>\r
- /// <param name="fpsNumerator">The rate numerator.</param>\r
- /// <param name="fpsDenominator">The rate denominator.</param>\r
- /// <param name="interlaced">True if x264 interlaced output is enabled.</param>\r
- /// <param name="fakeInterlaced">True if x264 fake interlacing is enabled.</param>\r
- /// <returns>True if the level is valid.</returns>\r
+ /// <param name="level">\r
+ /// The level to check.\r
+ /// </param>\r
+ /// <param name="width">\r
+ /// The output picture width.\r
+ /// </param>\r
+ /// <param name="height">\r
+ /// The output picture height.\r
+ /// </param>\r
+ /// <param name="fpsNumerator">\r
+ /// The rate numerator.\r
+ /// </param>\r
+ /// <param name="fpsDenominator">\r
+ /// The rate denominator.\r
+ /// </param>\r
+ /// <param name="interlaced">\r
+ /// True if x264 interlaced output is enabled.\r
+ /// </param>\r
+ /// <param name="fakeInterlaced">\r
+ /// True if x264 fake interlacing is enabled.\r
+ /// </param>\r
+ /// <returns>\r
+ /// True if the level is valid.\r
+ /// </returns>\r
public static bool IsH264LevelValid(string level, int width, int height, int fpsNumerator, int fpsDenominator, bool interlaced, bool fakeInterlaced)\r
{\r
return HBFunctions.hb_check_h264_level(\r
- level,\r
- width,\r
- height,\r
- fpsNumerator,\r
- fpsDenominator,\r
- interlaced ? 1 : 0,\r
+ level, \r
+ width, \r
+ height, \r
+ fpsNumerator, \r
+ fpsDenominator, \r
+ interlaced ? 1 : 0, \r
fakeInterlaced ? 1 : 0) == 0;\r
}\r
\r
/// <summary>\r
/// Creates an X264 options string from the given settings.\r
/// </summary>\r
- /// <param name="preset">The x264 preset.</param>\r
- /// <param name="tunes">The x264 tunes being used.</param>\r
- /// <param name="extraOptions">The extra options string.</param>\r
- /// <param name="profile">The H.264 profile.</param>\r
- /// <param name="level">The H.264 level.</param>\r
- /// <param name="width">The width of the final picture.</param>\r
- /// <param name="height">The height of the final picture.</param>\r
- /// <returns>The full x264 options string from the given inputs.</returns>\r
+ /// <param name="preset">\r
+ /// The x264 preset.\r
+ /// </param>\r
+ /// <param name="tunes">\r
+ /// The x264 tunes being used.\r
+ /// </param>\r
+ /// <param name="extraOptions">\r
+ /// The extra options string.\r
+ /// </param>\r
+ /// <param name="profile">\r
+ /// The H.264 profile.\r
+ /// </param>\r
+ /// <param name="level">\r
+ /// The H.264 level.\r
+ /// </param>\r
+ /// <param name="width">\r
+ /// The width of the final picture.\r
+ /// </param>\r
+ /// <param name="height">\r
+ /// The height of the final picture.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The full x264 options string from the given inputs.\r
+ /// </returns>\r
public static string CreateX264OptionsString(\r
- string preset,\r
- IList<string> tunes,\r
- string extraOptions,\r
- string profile,\r
- string level,\r
- int width,\r
+ string preset, \r
+ IList<string> tunes, \r
+ string extraOptions, \r
+ string profile, \r
+ string level, \r
+ int width, \r
int height)\r
{\r
if (width <= 0)\r
}\r
\r
IntPtr ptr = HBFunctions.hb_x264_param_unparse(\r
- preset,\r
- string.Join(",", tunes),\r
- extraOptions,\r
- profile,\r
- level,\r
- width,\r
+ preset, \r
+ string.Join(",", tunes), \r
+ extraOptions, \r
+ profile, \r
+ level, \r
+ width, \r
height);\r
\r
string x264Settings = Marshal.PtrToStringAnsi(ptr);\r
/// <summary>\r
/// Gets the total number of seconds on the given encode job.\r
/// </summary>\r
- /// <param name="job">The encode job to query.</param>\r
- /// <param name="title">The title being encoded.</param>\r
- /// <returns>The total number of seconds of video to encode.</returns>\r
+ /// <param name="job">\r
+ /// The encode job to query.\r
+ /// </param>\r
+ /// <param name="title">\r
+ /// The title being encoded.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The total number of seconds of video to encode.\r
+ /// </returns>\r
internal static double GetJobLengthSeconds(EncodeJob job, Title title)\r
{\r
switch (job.RangeType)\r
/// <summary>\r
/// Gets the number of audio samples used per frame for the given audio encoder.\r
/// </summary>\r
- /// <param name="encoderName">The encoder to query.</param>\r
- /// <returns>The number of audio samples used per frame for the given\r
- /// audio encoder.</returns>\r
+ /// <param name="encoderName">\r
+ /// The encoder to query.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The number of audio samples used per frame for the given\r
+ /// audio encoder.\r
+ /// </returns>\r
internal static int GetAudioSamplesPerFrame(string encoderName)\r
{\r
switch (encoderName)\r
/// <summary>\r
/// Gets the size in bytes for the audio with the given parameters.\r
/// </summary>\r
- /// <param name="job">The encode job.</param>\r
- /// <param name="lengthSeconds">The length of the encode in seconds.</param>\r
- /// <param name="title">The title to encode.</param>\r
- /// <param name="outputTrackList">The list of tracks to encode.</param>\r
- /// <returns>The size in bytes for the audio with the given parameters.</returns>\r
+ /// <param name="job">\r
+ /// The encode job.\r
+ /// </param>\r
+ /// <param name="lengthSeconds">\r
+ /// The length of the encode in seconds.\r
+ /// </param>\r
+ /// <param name="title">\r
+ /// The title to encode.\r
+ /// </param>\r
+ /// <param name="outputTrackList">\r
+ /// The list of tracks to encode.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The size in bytes for the audio with the given parameters.\r
+ /// </returns>\r
internal static long GetAudioSize(EncodeJob job, double lengthSeconds, Title title, List<Tuple<AudioEncoding, int>> outputTrackList)\r
{\r
long audioBytes = 0;\r
AudioEncoding encoding = outputTrack.Item1;\r
AudioTrack track = title.AudioTracks[outputTrack.Item2 - 1];\r
\r
- int samplesPerFrame = HandBrakeUtils.GetAudioSamplesPerFrame(encoding.Encoder);\r
+ int samplesPerFrame = GetAudioSamplesPerFrame(encoding.Encoder);\r
int audioBitrate;\r
\r
HBAudioEncoder audioEncoder = Encoders.GetAudioEncoder(encoding.Encoder);\r
else\r
{\r
outputBitrate = Encoders.GetDefaultBitrate(\r
- audioEncoder,\r
- encoding.SampleRateRaw == 0 ? track.SampleRate : encoding.SampleRateRaw,\r
+ audioEncoder, \r
+ encoding.SampleRateRaw == 0 ? track.SampleRate : encoding.SampleRateRaw, \r
Encoders.SanitizeMixdown(Encoders.GetMixdown(encoding.Mixdown), audioEncoder, track.ChannelLayout));\r
}\r
\r
return audioBytes;\r
}\r
\r
+ /// <summary>\r
+ /// Calculates the video bitrate for the given job and target size.\r
+ /// </summary>\r
+ /// <param name="job">\r
+ /// The encode job.\r
+ /// </param>\r
+ /// <param name="title">\r
+ /// The title.\r
+ /// </param>\r
+ /// <param name="sizeMB">\r
+ /// The target size in MB.\r
+ /// </param>\r
+ /// <param name="overallSelectedLengthSeconds">\r
+ /// The currently selected encode length. Used in preview\r
+ /// for calculating bitrate when the target size would be wrong.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The video bitrate in kbps.\r
+ /// </returns>\r
+ public static int CalculateBitrate(EncodeJob job, Title title, int sizeMB, double overallSelectedLengthSeconds = 0)\r
+ {\r
+ long availableBytes = ((long)sizeMB) * 1024 * 1024;\r
+\r
+ EncodingProfile profile = job.EncodingProfile;\r
+\r
+ double lengthSeconds = overallSelectedLengthSeconds > 0 ? overallSelectedLengthSeconds : GetJobLengthSeconds(job, title);\r
+ lengthSeconds += 1.5;\r
+\r
+ double outputFramerate;\r
+ if (profile.Framerate == 0)\r
+ {\r
+ outputFramerate = title.Framerate;\r
+ }\r
+ else\r
+ {\r
+ // Not sure what to do for VFR here hb_calc_bitrate never handled it...\r
+ // just use the peak for now.\r
+ outputFramerate = profile.Framerate;\r
+ }\r
+\r
+ long frames = (long)(lengthSeconds * outputFramerate);\r
+\r
+ availableBytes -= frames * ContainerOverheadPerFrame;\r
+\r
+ List<Tuple<AudioEncoding, int>> outputTrackList = GetOutputTracks(job, title);\r
+ availableBytes -= GetAudioSize(job, lengthSeconds, title, outputTrackList);\r
+\r
+ if (availableBytes < 0)\r
+ {\r
+ return 0;\r
+ }\r
+\r
+ // Video bitrate is in kilobits per second, or where 1 kbps is 1000 bits per second.\r
+ // So 1 kbps is 125 bytes per second.\r
+ return (int)(availableBytes / (125 * lengthSeconds));\r
+ }\r
+\r
+ /// <summary>\r
+ /// Gives estimated file size (in MB) of the given job and video bitrate.\r
+ /// </summary>\r
+ /// <param name="job">\r
+ /// The encode job.\r
+ /// </param>\r
+ /// <param name="title">\r
+ /// The title.\r
+ /// </param>\r
+ /// <param name="videoBitrate">\r
+ /// The video bitrate to be used (kbps).\r
+ /// </param>\r
+ /// <returns>\r
+ /// The estimated file size (in MB) of the given job and video bitrate.\r
+ /// </returns>\r
+ public static double CalculateFileSize(EncodeJob job, Title title, int videoBitrate)\r
+ {\r
+ long totalBytes = 0;\r
+\r
+ EncodingProfile profile = job.EncodingProfile;\r
+\r
+ double lengthSeconds = GetJobLengthSeconds(job, title);\r
+ lengthSeconds += 1.5;\r
+\r
+ double outputFramerate;\r
+ if (profile.Framerate == 0)\r
+ {\r
+ outputFramerate = title.Framerate;\r
+ }\r
+ else\r
+ {\r
+ // Not sure what to do for VFR here hb_calc_bitrate never handled it...\r
+ // just use the peak for now.\r
+ outputFramerate = profile.Framerate;\r
+ }\r
+\r
+ long frames = (long)(lengthSeconds * outputFramerate);\r
+\r
+ totalBytes += (long)(lengthSeconds * videoBitrate * 125);\r
+ totalBytes += frames * ContainerOverheadPerFrame;\r
+\r
+ List<Tuple<AudioEncoding, int>> outputTrackList = GetOutputTracks(job, title);\r
+ totalBytes += GetAudioSize(job, lengthSeconds, title, outputTrackList);\r
+\r
+ return (double)totalBytes / 1024 / 1024;\r
+ }\r
+\r
/// <summary>\r
/// Sends the message logged event to any registered listeners.\r
/// </summary>\r
- /// <param name="message">The message to send.</param>\r
+ /// <param name="message">\r
+ /// The message to send.\r
+ /// </param>\r
private static void SendMessageEvent(string message)\r
{\r
if (MessageLogged != null)\r
MessageLogged(null, new MessageLoggedEventArgs { Message = message });\r
}\r
\r
- System.Diagnostics.Debug.WriteLine(message);\r
+ Debug.WriteLine(message);\r
}\r
\r
/// <summary>\r
/// Sends the error logged event to any registered listeners.\r
/// </summary>\r
- /// <param name="message">The message to send</param>\r
+ /// <param name="message">\r
+ /// The message to send\r
+ /// </param>\r
private static void SendErrorEvent(string message)\r
{\r
if (ErrorLogged != null)\r
ErrorLogged(null, new MessageLoggedEventArgs { Message = message });\r
}\r
\r
- System.Diagnostics.Debug.WriteLine("ERROR: " + message);\r
+ Debug.WriteLine("ERROR: " + message);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Gets a list of encodings and target track indices (1-based).\r
+ /// </summary>\r
+ /// <param name="job">The encode job</param>\r
+ /// <param name="title">The title the job is meant to encode.</param>\r
+ /// <returns>A list of encodings and target track indices (1-based).</returns>\r
+ private static List<Tuple<AudioEncoding, int>> GetOutputTracks(EncodeJob job, Title title)\r
+ {\r
+ var list = new List<Tuple<AudioEncoding, int>>();\r
+\r
+ foreach (AudioEncoding encoding in job.EncodingProfile.AudioEncodings)\r
+ {\r
+ if (encoding.InputNumber == 0)\r
+ {\r
+ // Add this encoding for all chosen tracks\r
+ foreach (int chosenTrack in job.ChosenAudioTracks)\r
+ {\r
+ // In normal cases we'll never have a chosen audio track that doesn't exist but when batch encoding\r
+ // we just choose the first audio track without checking if it exists.\r
+ if (chosenTrack <= title.AudioTracks.Count)\r
+ {\r
+ list.Add(new Tuple<AudioEncoding, int>(encoding, chosenTrack));\r
+ }\r
+ }\r
+ }\r
+ else if (encoding.InputNumber <= job.ChosenAudioTracks.Count)\r
+ {\r
+ // Add this encoding for the specified track, if it exists\r
+ int trackNumber = job.ChosenAudioTracks[encoding.InputNumber - 1];\r
+\r
+ // In normal cases we'll never have a chosen audio track that doesn't exist but when batch encoding\r
+ // we just choose the first audio track without checking if it exists.\r
+ if (trackNumber <= title.AudioTracks.Count)\r
+ {\r
+ list.Add(new Tuple<AudioEncoding, int>(encoding, trackNumber));\r
+ }\r
+ }\r
+ }\r
+\r
+ return list;\r
}\r
}\r
}\r
\r
return GreatestCommonFactor(a, b % a);\r
}\r
-\r
- /// <summary>\r
- /// Determines if the given audio encoder is a passthrough encoder choice.\r
- /// </summary>\r
- /// <param name="encoder">The audio encoder to examine.</param>\r
- /// <returns>True if the encoder is passthrough.</returns>\r
- public static bool IsPassthrough(AudioEncoder encoder)\r
- {\r
- return encoder == AudioEncoder.Ac3Passthrough ||\r
- encoder == AudioEncoder.DtsHDPassthrough ||\r
- encoder == AudioEncoder.DtsPassthrough ||\r
- encoder == AudioEncoder.Mp3Passthru || \r
- encoder == AudioEncoder.AacPassthru ||\r
- encoder == AudioEncoder.Passthrough;\r
- }\r
}\r
}\r
/// </summary>\r
int FeatureTitle { get; }\r
\r
- /// <summary>\r
- /// Gets the number of previews created during scan.\r
- /// </summary>\r
- int PreviewCount { get; }\r
-\r
/// <summary>\r
/// Gets the list of titles on this instance.\r
/// </summary>\r
/// <param name="verbosity">The code for the logging verbosity to use.</param>\r
void Initialize(int verbosity);\r
\r
- /// <summary>\r
- /// Calculates the video bitrate for the given job and target size.\r
- /// </summary>\r
- /// <param name="job">\r
- /// The encode job.\r
- /// </param>\r
- /// <param name="sizeMB">\r
- /// The target size in MB.\r
- /// </param>\r
- /// <param name="overallSelectedLengthSeconds">\r
- /// The currently selected encode length. Used in preview\r
- /// for calculating bitrate when the target size would be wrong.\r
- /// </param>\r
- /// <returns>\r
- /// The video bitrate in kbps.\r
- /// </returns>\r
- int CalculateBitrate(EncodeJob job, int sizeMB, double overallSelectedLengthSeconds = 0);\r
-\r
- /// <summary>\r
- /// Gives estimated file size (in MB) of the given job and video bitrate.\r
- /// </summary>\r
- /// <param name="job">\r
- /// The encode job.\r
- /// </param>\r
- /// <param name="videoBitrate">\r
- /// The video bitrate to be used (kbps).\r
- /// </param>\r
- /// <returns>\r
- /// The estimated file size (in MB) of the given job and video bitrate.\r
- /// </returns>\r
- double CalculateFileSize(EncodeJob job, int videoBitrate);\r
-\r
/// <summary>\r
/// Frees any resources associated with this object.\r
/// </summary>\r
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CompareOfFloatsByEqualityOperator/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InconsistentNaming/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=LocalizableElement/@EntryIndexedValue">DO_NOT_SHOW</s:String>
+ <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=LoopCanBeConvertedToQuery/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantNameQualifier/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantStringFormatCall/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantThisQualifier/@EntryIndexedValue">DO_NOT_SHOW</s:String>