// --------------------------------------------------------------------------------------------------------------------
//
// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
//
//
// A Converter to provide the available audio bitrate options.
//
// --------------------------------------------------------------------------------------------------------------------
namespace HandBrakeWPF.Converters.Audio
{
using System;
using System.Globalization;
using System.Windows.Data;
using System.Collections.Generic;
using System.Linq;
using HandBrake.ApplicationServices.Model.Encoding;
using HandBrake.Interop.Model.Encoding;
///
/// A Converter to provide the available audio bitrate options.
///
public class AudioBitrateConverter : IValueConverter
{
///
/// The samplerates.
///
readonly Dictionary samplerates = new Dictionary
{
{ 8, 8000 },
{ 11.025, 11025 },
{ 12, 12000 },
{ 16, 16000 },
{ 22.05, 22050 },
{ 24, 24000 },
{ 32, 32000 },
{ 44.1, 44100 },
{ 48, 48000 }
};
///
/// Converts source values to a value for the binding target. The data binding engine calls this method when it propagates the values from source bindings to the binding target.
///
///
/// A converted value.If the method returns null, the valid null value is used.A return value of . indicates that the converter did not produce a value, and that the binding will use the if it is available, or else will use the default value.A return value of . indicates that the binding does not transfer the value or use the or the default value.
///
///
/// The value.
///
///
/// The type of the binding target property.
///
///
/// The converter parameter to use.
///
///
/// The culture to use in the converter.
///
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Base set of bitrates available.
List bitrates = new List { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 640, 768, 960, 1152, 1344, 1536 };
int max = 160;
int low = 32;
AudioTrack track = value as AudioTrack;
if (track != null)
{
int samplerate = this.GetBestSampleRate(track);
int srShift = this.GetSamplerateShift(samplerate);
int lfeCount = this.GetLowFreqChannelCount(track.MixDown);
int channels = this.GetDiscreteChannelCount(track.MixDown) - lfeCount;
switch (track.Encoder)
{
case AudioEncoder.ffaac:
low = ((channels + lfeCount) * 32);
max = ((channels + lfeCount) * ((192 + (64 * ((samplerate << srShift) >= 44100 ? 1 : 0))) >> srShift));
break;
case AudioEncoder.Lame:
low = 8 + (24 * (srShift < 1 ? 1 : 0) );
max = 64 + (96 * (srShift < 2 ? 1 : 0)) + (160 * (srShift < 1 ? 1 : 0));
break;
case AudioEncoder.Vorbis:
low = (channels + lfeCount) * (14 + (8 * (srShift < 2 ? 1 : 0)) + (6 * (srShift < 1 ? 1 : 0)));
max = (channels + lfeCount) * (32 + (54 * (srShift < 2 ? 1 : 0)) + (104 * (srShift < 1 ? 1 : 0)) + (50 * (samplerate >= 44100 ? 1 : 0)));
break;
case AudioEncoder.Ac3:
low = 224 * channels / 5;
max = 640;
break;
case AudioEncoder.Ac3Passthrough:
case AudioEncoder.DtsPassthrough:
case AudioEncoder.DtsHDPassthrough:
case AudioEncoder.AacPassthru:
case AudioEncoder.Mp3Passthru:
case AudioEncoder.Passthrough:
case AudioEncoder.ffflac:
case AudioEncoder.ffflac24:
max = 1536; // Since we don't care, just set it to the max.
break;
case AudioEncoder.fdkaac:
low = channels * samplerate * 2 / 3000;
max = channels * samplerate * 6 / 1000;
break;
case AudioEncoder.fdkheaac:
low = (channels * (12 + (4 * (samplerate >= 44100 ? 1 : 0))));
max = (channels - (channels > 2 ? 1 : 0)) * (48 + (16 * (samplerate >= 22050 ? 1 : 0)));
break;
default:
max = 768;
break;
}
// Bring the bitrate down in-line with the max.
if (track.Bitrate < low)
{
track.Bitrate = low;
}
if (track.Bitrate > max)
{
track.Bitrate = max;
}
}
return bitrates.Where(bitrate => bitrate <= max && bitrate >= low);
}
///
/// The get channel count.
///
///
/// The mixdown.
///
///
/// The System.Int32.
///
private int GetDiscreteChannelCount(Mixdown mixdown)
{
switch (mixdown)
{
case Mixdown.Five_2_LFE:
case Mixdown.SevenPoint1Channels:
return 8;
case Mixdown.SixPoint1Channels:
return 7;
case Mixdown.FivePoint1Channels:
return 6;
case Mixdown.Mono:
case Mixdown.LeftOnly:
case Mixdown.RightOnly:
return 1;
case Mixdown.None:
return 0;
default:
return 2;
}
}
///
/// The get low freq channel count.
///
///
/// The mixdown.
///
///
/// The System.Int32.
///
private int GetLowFreqChannelCount(Mixdown mixdown)
{
switch (mixdown)
{
case Mixdown.FivePoint1Channels:
case Mixdown.SixPoint1Channels:
case Mixdown.SevenPoint1Channels:
case Mixdown.Five_2_LFE:
return 1;
default:
return 0;
}
}
///
/// The get samplerate shift.
///
///
/// The samplerate.
///
///
/// The System.Int32.
///
private int GetSamplerateShift(int samplerate)
{
/* sr_shift: 0 -> 48000, 44100, 32000 Hz
* 1 -> 24000, 22050, 16000 Hz
* 2 -> 12000, 11025, 8000 Hz
*
* also, since samplerates are sanitized downwards:
*
* (samplerate < 32000) implies (samplerate <= 24000)
*/
return ((samplerate < 16000) ? 2 : (samplerate < 32000) ? 1 : 0);
}
///
/// The get best sample rate.
///
///
/// The track.
///
///
/// The System.Double.
///
private int GetBestSampleRate(AudioTrack track)
{
int samplerate = 48000; // Default to 48
// Try get the users selected sample rate
if (!track.SampleRate.Equals(0.0d))
{
samplerate = this.samplerates[track.SampleRate];
}
else if (track.ScannedTrack != null && track.ScannedTrack.SampleRate != 0) // If it's auto, try get the source
{
samplerate = track.ScannedTrack.SampleRate;
}
// THen Sanitize to make sure it's valid
int bestSamplerate;
if ((samplerate < 32000) && (track.Encoder == AudioEncoder.Ac3))
{
// AC-3 < 32 kHz suffers from poor hardware compatibility
bestSamplerate = 32000;
}
else if ((samplerate < 16000) && (track.Encoder == AudioEncoder.fdkheaac))
{
bestSamplerate = 16000;
}
else
{
bestSamplerate = samplerate;
foreach (KeyValuePair item in this.samplerates)
{
// valid samplerate
if (bestSamplerate.Equals(item.Value))
break;
// samplerate is higher than the next valid samplerate,
// or lower than the lowest valid samplerate
if (bestSamplerate > item.Value && bestSamplerate < this.samplerates.First().Value)
{
bestSamplerate = item.Value;
break;
}
}
}
return bestSamplerate;
}
///
/// The convert back.
///
///
/// The value.
///
///
/// The target type.
///
///
/// The parameter.
///
///
/// The culture.
///
///
/// The System.Object.
///
///
/// We don't use this.
///
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}