summaryrefslogtreecommitdiffstats
path: root/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs
diff options
context:
space:
mode:
authorsr55 <[email protected]>2015-01-09 21:15:46 +0000
committersr55 <[email protected]>2015-01-09 21:15:46 +0000
commit152cabeebf37e9f45c49769e8abe64cd5867ad86 (patch)
treec4619fa1725be90368a5dd52d15b803e6afb4b0c /win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs
parente224d30a0d2dad76e501ff5d25e90f1b39c73807 (diff)
WinGui: Further API tidyup in the interop library. Moving some filesize calculation code into HandBrakeUtils. It's now the responsibility of the consumer to provide a valid title.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6705 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs')
-rw-r--r--win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs324
1 files changed, 264 insertions, 60 deletions
diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs
index fb92c3783..c1f5a5cad 100644
--- a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs
+++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs
@@ -11,19 +11,15 @@ namespace HandBrake.Interop
{
using System;
using System.Collections.Generic;
- using System.Linq;
+ using System.Diagnostics;
using System.Runtime.InteropServices;
using HandBrake.Interop.EventArgs;
using HandBrake.Interop.HbLib;
- using HandBrake.Interop.Json.Anamorphic;
- using HandBrake.Interop.Json.Scan;
using HandBrake.Interop.Model;
using HandBrake.Interop.Model.Encoding;
using HandBrake.Interop.Model.Scan;
- using Newtonsoft.Json;
-
/// <summary>
/// HandBrake Interop Utilities
/// </summary>
@@ -109,7 +105,9 @@ namespace HandBrake.Interop
/// <summary>
/// Enables or disables LibDVDNav. If disabled libdvdread will be used instead.
/// </summary>
- /// <param name="enableDvdNav">True to enable LibDVDNav.</param>
+ /// <param name="enableDvdNav">
+ /// True to enable LibDVDNav.
+ /// </param>
public static void SetDvdNav(bool enableDvdNav)
{
HBFunctions.hb_dvd_set_dvdnav(enableDvdNav ? 1 : 0);
@@ -142,7 +140,9 @@ namespace HandBrake.Interop
/// <summary>
/// Handles log messages from HandBrake.
/// </summary>
- /// <param name="message">The log message (including newline).</param>
+ /// <param name="message">
+ /// The log message (including newline).
+ /// </param>
public static void LoggingHandler(string message)
{
if (!string.IsNullOrEmpty(message))
@@ -160,7 +160,9 @@ namespace HandBrake.Interop
/// <summary>
/// Handles errors from HandBrake.
/// </summary>
- /// <param name="message">The error message.</param>
+ /// <param name="message">
+ /// The error message.
+ /// </param>
public static void ErrorHandler(string message)
{
if (!string.IsNullOrEmpty(message))
@@ -196,44 +198,76 @@ namespace HandBrake.Interop
/// <summary>
/// Checks to see if the given H.264 level is valid given the inputs.
/// </summary>
- /// <param name="level">The level to check.</param>
- /// <param name="width">The output picture width.</param>
- /// <param name="height">The output picture height.</param>
- /// <param name="fpsNumerator">The rate numerator.</param>
- /// <param name="fpsDenominator">The rate denominator.</param>
- /// <param name="interlaced">True if x264 interlaced output is enabled.</param>
- /// <param name="fakeInterlaced">True if x264 fake interlacing is enabled.</param>
- /// <returns>True if the level is valid.</returns>
+ /// <param name="level">
+ /// The level to check.
+ /// </param>
+ /// <param name="width">
+ /// The output picture width.
+ /// </param>
+ /// <param name="height">
+ /// The output picture height.
+ /// </param>
+ /// <param name="fpsNumerator">
+ /// The rate numerator.
+ /// </param>
+ /// <param name="fpsDenominator">
+ /// The rate denominator.
+ /// </param>
+ /// <param name="interlaced">
+ /// True if x264 interlaced output is enabled.
+ /// </param>
+ /// <param name="fakeInterlaced">
+ /// True if x264 fake interlacing is enabled.
+ /// </param>
+ /// <returns>
+ /// True if the level is valid.
+ /// </returns>
public static bool IsH264LevelValid(string level, int width, int height, int fpsNumerator, int fpsDenominator, bool interlaced, bool fakeInterlaced)
{
return HBFunctions.hb_check_h264_level(
- level,
- width,
- height,
- fpsNumerator,
- fpsDenominator,
- interlaced ? 1 : 0,
+ level,
+ width,
+ height,
+ fpsNumerator,
+ fpsDenominator,
+ interlaced ? 1 : 0,
fakeInterlaced ? 1 : 0) == 0;
}
/// <summary>
/// Creates an X264 options string from the given settings.
/// </summary>
- /// <param name="preset">The x264 preset.</param>
- /// <param name="tunes">The x264 tunes being used.</param>
- /// <param name="extraOptions">The extra options string.</param>
- /// <param name="profile">The H.264 profile.</param>
- /// <param name="level">The H.264 level.</param>
- /// <param name="width">The width of the final picture.</param>
- /// <param name="height">The height of the final picture.</param>
- /// <returns>The full x264 options string from the given inputs.</returns>
+ /// <param name="preset">
+ /// The x264 preset.
+ /// </param>
+ /// <param name="tunes">
+ /// The x264 tunes being used.
+ /// </param>
+ /// <param name="extraOptions">
+ /// The extra options string.
+ /// </param>
+ /// <param name="profile">
+ /// The H.264 profile.
+ /// </param>
+ /// <param name="level">
+ /// The H.264 level.
+ /// </param>
+ /// <param name="width">
+ /// The width of the final picture.
+ /// </param>
+ /// <param name="height">
+ /// The height of the final picture.
+ /// </param>
+ /// <returns>
+ /// The full x264 options string from the given inputs.
+ /// </returns>
public static string CreateX264OptionsString(
- string preset,
- IList<string> tunes,
- string extraOptions,
- string profile,
- string level,
- int width,
+ string preset,
+ IList<string> tunes,
+ string extraOptions,
+ string profile,
+ string level,
+ int width,
int height)
{
if (width <= 0)
@@ -247,12 +281,12 @@ namespace HandBrake.Interop
}
IntPtr ptr = HBFunctions.hb_x264_param_unparse(
- preset,
- string.Join(",", tunes),
- extraOptions,
- profile,
- level,
- width,
+ preset,
+ string.Join(",", tunes),
+ extraOptions,
+ profile,
+ level,
+ width,
height);
string x264Settings = Marshal.PtrToStringAnsi(ptr);
@@ -263,9 +297,15 @@ namespace HandBrake.Interop
/// <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>
+ /// <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)
@@ -292,9 +332,13 @@ namespace HandBrake.Interop
/// <summary>
/// Gets the number of audio samples used per frame for the given audio encoder.
/// </summary>
- /// <param name="encoderName">The encoder to query.</param>
- /// <returns>The number of audio samples used per frame for the given
- /// audio encoder.</returns>
+ /// <param name="encoderName">
+ /// The encoder to query.
+ /// </param>
+ /// <returns>
+ /// The number of audio samples used per frame for the given
+ /// audio encoder.
+ /// </returns>
internal static int GetAudioSamplesPerFrame(string encoderName)
{
switch (encoderName)
@@ -322,11 +366,21 @@ namespace HandBrake.Interop
/// <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>
+ /// <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;
@@ -336,7 +390,7 @@ namespace HandBrake.Interop
AudioEncoding encoding = outputTrack.Item1;
AudioTrack track = title.AudioTracks[outputTrack.Item2 - 1];
- int samplesPerFrame = HandBrakeUtils.GetAudioSamplesPerFrame(encoding.Encoder);
+ int samplesPerFrame = GetAudioSamplesPerFrame(encoding.Encoder);
int audioBitrate;
HBAudioEncoder audioEncoder = Encoders.GetAudioEncoder(encoding.Encoder);
@@ -361,8 +415,8 @@ namespace HandBrake.Interop
else
{
outputBitrate = Encoders.GetDefaultBitrate(
- audioEncoder,
- encoding.SampleRateRaw == 0 ? track.SampleRate : encoding.SampleRateRaw,
+ audioEncoder,
+ encoding.SampleRateRaw == 0 ? track.SampleRate : encoding.SampleRateRaw,
Encoders.SanitizeMixdown(Encoders.GetMixdown(encoding.Mixdown), audioEncoder, track.ChannelLayout));
}
@@ -380,9 +434,115 @@ namespace HandBrake.Interop
}
/// <summary>
+ /// Calculates the video bitrate for the given job and target size.
+ /// </summary>
+ /// <param name="job">
+ /// The encode job.
+ /// </param>
+ /// <param name="title">
+ /// The title.
+ /// </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 static int CalculateBitrate(EncodeJob job, Title title, int sizeMB, double overallSelectedLengthSeconds = 0)
+ {
+ long availableBytes = ((long)sizeMB) * 1024 * 1024;
+
+ EncodingProfile profile = job.EncodingProfile;
+
+ double lengthSeconds = overallSelectedLengthSeconds > 0 ? overallSelectedLengthSeconds : 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 * ContainerOverheadPerFrame;
+
+ List<Tuple<AudioEncoding, int>> outputTrackList = GetOutputTracks(job, title);
+ availableBytes -= 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="title">
+ /// The title.
+ /// </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 static double CalculateFileSize(EncodeJob job, Title title, int videoBitrate)
+ {
+ long totalBytes = 0;
+
+ EncodingProfile profile = job.EncodingProfile;
+
+ double lengthSeconds = 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 * ContainerOverheadPerFrame;
+
+ List<Tuple<AudioEncoding, int>> outputTrackList = GetOutputTracks(job, title);
+ totalBytes += GetAudioSize(job, lengthSeconds, title, outputTrackList);
+
+ return (double)totalBytes / 1024 / 1024;
+ }
+
+ /// <summary>
/// Sends the message logged event to any registered listeners.
/// </summary>
- /// <param name="message">The message to send.</param>
+ /// <param name="message">
+ /// The message to send.
+ /// </param>
private static void SendMessageEvent(string message)
{
if (MessageLogged != null)
@@ -390,13 +550,15 @@ namespace HandBrake.Interop
MessageLogged(null, new MessageLoggedEventArgs { Message = message });
}
- System.Diagnostics.Debug.WriteLine(message);
+ Debug.WriteLine(message);
}
/// <summary>
/// Sends the error logged event to any registered listeners.
/// </summary>
- /// <param name="message">The message to send</param>
+ /// <param name="message">
+ /// The message to send
+ /// </param>
private static void SendErrorEvent(string message)
{
if (ErrorLogged != null)
@@ -404,7 +566,49 @@ namespace HandBrake.Interop
ErrorLogged(null, new MessageLoggedEventArgs { Message = message });
}
- System.Diagnostics.Debug.WriteLine("ERROR: " + message);
+ Debug.WriteLine("ERROR: " + message);
+ }
+
+ /// <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 static 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)
+ {
+ // 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 (chosenTrack <= title.AudioTracks.Count)
+ {
+ 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;
}
}
}