return x264Settings;\r
}\r
\r
- /// <summary>\r
- /// Gets the total number of seconds on the given encode job.\r
- /// </summary>\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
- {\r
- // case VideoRangeType.All:\r
- // return title.Duration.TotalSeconds;\r
- case VideoRangeType.Chapters:\r
- TimeSpan duration = TimeSpan.Zero;\r
- for (int i = job.ChapterStart; i <= job.ChapterEnd; i++)\r
- {\r
- duration += title.Chapters[i - 1].Duration;\r
- }\r
-\r
- return duration.TotalSeconds;\r
- case VideoRangeType.Seconds:\r
- return job.SecondsEnd - job.SecondsStart;\r
- case VideoRangeType.Frames:\r
- return (job.FramesEnd - job.FramesStart) / title.Framerate;\r
- }\r
-\r
- return 0;\r
- }\r
-\r
- /// <summary>\r
- /// Gets the number of audio samples used per frame for the given audio encoder.\r
- /// </summary>\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
- {\r
- case "faac":\r
- case "ffaac":\r
- case "copy:aac":\r
- case "vorbis":\r
- return 1024;\r
- case "lame":\r
- case "copy:mp3":\r
- return 1152;\r
- case "ffac3":\r
- case "copy":\r
- case "copy:ac3":\r
- case "copy:dts":\r
- case "copy:dtshd":\r
- return 1536;\r
- }\r
-\r
- // Unknown encoder; make a guess.\r
- return 1536;\r
- }\r
-\r
- /// <summary>\r
- /// Gets the size in bytes for the audio with the given parameters.\r
- /// </summary>\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
-\r
- foreach (Tuple<AudioEncoding, int> outputTrack in outputTrackList)\r
- {\r
- AudioEncoding encoding = outputTrack.Item1;\r
- AudioTrack track = title.AudioTracks[outputTrack.Item2 - 1];\r
-\r
- int samplesPerFrame = GetAudioSamplesPerFrame(encoding.Encoder);\r
- int audioBitrate;\r
-\r
- HBAudioEncoder audioEncoder = HandBrakeEncoderHelpers.GetAudioEncoder(encoding.Encoder);\r
-\r
- if (audioEncoder.IsPassthrough)\r
- {\r
- // Input bitrate is in bits/second.\r
- audioBitrate = track.Bitrate / 8;\r
- }\r
- else if (encoding.EncodeRateType == AudioEncodeRateType.Quality)\r
- {\r
- // Can't predict size of quality targeted audio encoding.\r
- audioBitrate = 0;\r
- }\r
- else\r
- {\r
- int outputBitrate;\r
- if (encoding.Bitrate > 0)\r
- {\r
- outputBitrate = encoding.Bitrate;\r
- }\r
- else\r
- {\r
- outputBitrate = HandBrakeEncoderHelpers.GetDefaultBitrate(\r
- audioEncoder, \r
- encoding.SampleRateRaw == 0 ? track.SampleRate : encoding.SampleRateRaw,\r
- HandBrakeEncoderHelpers.SanitizeMixdown(HandBrakeEncoderHelpers.GetMixdown(encoding.Mixdown), audioEncoder, track.ChannelLayout));\r
- }\r
-\r
- // Output bitrate is in kbps.\r
- audioBitrate = outputBitrate * 1000 / 8;\r
- }\r
-\r
- audioBytes += (long)(lengthSeconds * audioBitrate);\r
-\r
- // Audio overhead\r
- audioBytes += encoding.SampleRateRaw * ContainerOverheadPerFrame / samplesPerFrame;\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
- EncodeJob profile = job;\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
- EncodeJob profile = job;\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
\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.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