Audio and MIDI library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

250 lines
9.4 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using NAudio.MediaFoundation;
using NAudio.Wave;
using NAudioWpfDemo.ViewModel;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using SaveFileDialog = Microsoft.Win32.SaveFileDialog;
namespace NAudioWpfDemo.MediaFoundationEncode
{
internal class MediaFoundationEncodeViewModel : ViewModelBase, IDisposable
{
private readonly Dictionary<Guid, List<MediaTypeViewModel>> allMediaTypes;
private EncoderViewModel selectedOutputFormat;
private MediaTypeViewModel selectedMediaType;
private string inputFile;
private string inputFormat;
private WaveFormat inputWaveFormat;
public List<EncoderViewModel> OutputFormats { get; }
public List<MediaTypeViewModel> SupportedMediaTypes { get; private set; }
public ICommand EncodeCommand { get; }
public ICommand SelectInputFileCommand { get; }
public MediaFoundationEncodeViewModel()
{
MediaFoundationApi.Startup();
allMediaTypes = new Dictionary<Guid, List<MediaTypeViewModel>>();
SupportedMediaTypes = new List<MediaTypeViewModel>();
EncodeCommand = new DelegateCommand(Encode);
SelectInputFileCommand = new DelegateCommand(SelectInputFile);
// TODO: fill this by asking the encoders what they can do
OutputFormats = new List<EncoderViewModel>
{
new EncoderViewModel() { Name = "AAC", Guid = AudioSubtypes.MFAudioFormat_AAC, Extension = ".mp4" }, // Windows 8 can do a .aac extension as well
new EncoderViewModel() { Name = "Windows Media Audio", Guid = AudioSubtypes.MFAudioFormat_WMAudioV8, Extension = ".wma" },
new EncoderViewModel() { Name = "Windows Media Audio Professional", Guid = AudioSubtypes.MFAudioFormat_WMAudioV9, Extension = ".wma" },
new EncoderViewModel() { Name = "MP3", Guid = AudioSubtypes.MFAudioFormat_MP3, Extension = ".mp3" },
new EncoderViewModel() { Name = "Windows Media Audio Voice", Guid = AudioSubtypes.MFAudioFormat_MSP1, Extension = ".wma" },
new EncoderViewModel() { Name = "Windows Media Audio Lossless", Guid = AudioSubtypes.MFAudioFormat_WMAudio_Lossless, Extension = ".wma" },
new EncoderViewModel() { Name = "FLAC", Guid = AudioSubtypes.MFAudioFormat_FLAC, Extension = ".flac" },
new EncoderViewModel() { Name = "Apple Lossless (ALAC)", Guid = AudioSubtypes.MFAudioFormat_ALAC, Extension = ".m4a" },
new EncoderViewModel() { Name = "Fake for testing", Guid = Guid.NewGuid(), Extension = ".xyz" }
};
SelectedOutputFormat = OutputFormats[0];
}
private void SelectInputFile()
{
var ofd = new OpenFileDialog();
ofd.Filter = "Audio files|*.mp3;*.wav;*.wma;*.aiff;*.aac";
if (ofd.ShowDialog() == true)
{
if (TryOpenInputFile(ofd.FileName))
{
InputFile = ofd.FileName;
SetMediaTypes();
}
}
}
private bool TryOpenInputFile(string file)
{
bool isValid = false;
try
{
using (var reader = new MediaFoundationReader(file))
{
InputFormat = reader.WaveFormat.ToString();
inputWaveFormat = reader.WaveFormat;
}
isValid = true;
}
catch (Exception e)
{
MessageBox.Show($"Not a supported input file ({e.Message})");
}
return isValid;
}
public string InputFile
{
get => inputFile;
set
{
if (inputFile != value)
{
inputFile = value;
OnPropertyChanged(nameof(InputFile));
}
}
}
public string InputFormat
{
get => inputFormat;
set
{
if (inputFormat != value)
{
inputFormat = value;
OnPropertyChanged(nameof(InputFormat));
}
}
}
public EncoderViewModel SelectedOutputFormat
{
get => selectedOutputFormat;
set {
if (selectedOutputFormat != value)
{
selectedOutputFormat = value;
SetMediaTypes();
OnPropertyChanged("SelectedOutputFormat");
}
}
}
private void SetMediaTypes()
{
if (!allMediaTypes.ContainsKey(SelectedOutputFormat.Guid))
{
TryGetSupportedMediaTypes();
}
FilterSupportedMediaTypes();
OnPropertyChanged(nameof(SupportedMediaTypes));
SelectedMediaType = SupportedMediaTypes.FirstOrDefault();
}
private void FilterSupportedMediaTypes()
{
//SupportedMediaTypes.Clear();
SupportedMediaTypes = new List<MediaTypeViewModel>();
if (inputWaveFormat == null)
{
SupportedMediaTypes.Add(new MediaTypeViewModel() {Name="Select an input file"});
return;
}
SupportedMediaTypes = allMediaTypes[SelectedOutputFormat.Guid]
.Where(m => m.MediaType != null)
.Where(m => m.MediaType.SampleRate == inputWaveFormat.SampleRate)
.Where(m => m.MediaType.ChannelCount == inputWaveFormat.Channels)
.ToList();
}
private void TryGetSupportedMediaTypes()
{
var list = MediaFoundationEncoder.GetOutputMediaTypes(SelectedOutputFormat.Guid)
.Select(mf => new MediaTypeViewModel(mf))
.ToList();
if (list.Count == 0)
{
list.Add(new MediaTypeViewModel() {Name = "Not Supported", Description = "No encoder found for this output type"});
}
allMediaTypes[SelectedOutputFormat.Guid] = list;
}
public MediaTypeViewModel SelectedMediaType
{
get => selectedMediaType;
set
{
if (selectedMediaType != value)
{
selectedMediaType = value;
OnPropertyChanged(nameof(SelectedMediaType));
}
}
}
private void Encode()
{
if (String.IsNullOrEmpty(InputFile) || !File.Exists(InputFile))
{
MessageBox.Show("Please select a valid input file to convert");
return;
}
if (SelectedMediaType == null || SelectedMediaType.MediaType == null)
{
MessageBox.Show("Please select a valid output format");
return;
}
using (var reader = new MediaFoundationReader(InputFile))
{
string outputUrl = SelectSaveFile(SelectedOutputFormat.Name, SelectedOutputFormat.Extension);
if (outputUrl == null) return;
using (var encoder = new MediaFoundationEncoder(SelectedMediaType.MediaType))
{
try
{
encoder.Encode(outputUrl, reader);
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Failed to encode");
}
}
}
}
private string SelectSaveFile(string formatName, string extension)
{
var sfd = new SaveFileDialog();
sfd.FileName = Path.GetFileNameWithoutExtension(InputFile) + " converted" + extension;
sfd.Filter = formatName + "|*" + extension;
//return (sfd.ShowDialog() == true) ? new Uri(sfd.FileName).AbsoluteUri : null;
return (sfd.ShowDialog() == true) ? sfd.FileName : null;
}
public void Dispose()
{
MediaFoundationApi.Shutdown();
}
}
enum AacPayloadType
{
/// <summary>
/// The stream contains raw_data_block elements only.
/// </summary>
RawData = 0,
/// <summary>
/// Audio Data Transport Stream (ADTS). The stream contains an adts_sequence, as defined by MPEG-2.
/// </summary>
Adts = 1,
/// <summary>
/// Audio Data Interchange Format (ADIF). The stream contains an adif_sequence, as defined by MPEG-2.
/// </summary>
Adif = 2,
/// <summary>
/// The stream contains an MPEG-4 audio transport stream with a synchronization layer (LOAS) and a multiplex layer (LATM).
/// </summary>
LoasLatm = 3
}
internal class EncoderViewModel : ViewModelBase
{
public string Name { get; set; }
public Guid Guid { get; set; }
public string Extension { get; set; }
}
}