I'm developing a WPF application, where I have to play audio. I receive the audio data in .mp4
format (in a byte array) and the only restriction is that I can't write it out to the hard disk.
I found couple of solutions for playing the .mp4
format, for example with WMPLib.WindowsMediaPlayer
, but I can't give a byte array, or stream to this library, to play the audio. It just accepts the file path.
Then I found the System.Media.SoundPlayer
, which can play audio from a stream, but just in .wav
format. I started to search for solutions to convert from mp4 to wav. I found the NAudio
library and I could make the conversion the following way:
using (var data = new MediaFoundationReader(filePath)) {
var stream = new MemoryStream();
WaveFileWriter.WriteWavFileToStream(stream, data);
}
The problem with this is that I can instantiate the MediaFoundationReader
just with a file path parameter. I didn't find any way to create it without using files. I think this was also a dead end.
So, any suggestion would be helpful about how can I convert audio in memory, or maybe how can I play directly the .mp4
file from a byte array or stream?
Finally I found a solution which converts to an .mp3
format, but it can also convert to .wav
. I could use the uwp transcode API the following way:
public static async void ConvertMp4ToMp3(byte[] mp4Data, Action<Stream> doneCallback) {
MediaEncodingProfile profile = MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High);
var inputStream = new MemoryRandomAccessStream(mp4Data);
var outputStream = new InMemoryRandomAccessStream();
MediaTranscoder transcoder = new MediaTranscoder();
PrepareTranscodeResult prepareOperation = await transcoder.PrepareStreamTranscodeAsync(inputStream, outputStream, profile);
if (prepareOperation.CanTranscode) {
//start to convert
var transcodeOperation = prepareOperation.TranscodeAsync();
//registers completed event handler
transcodeOperation.Completed += (IAsyncActionWithProgress<double> asyncInfo, AsyncStatus status) => {
asyncInfo.GetResults();
var stream = outputStream.AsStream();
stream.Position = 0;
doneCallback(stream);
};
} else {
doneCallback(null);
}
}
The imports:
using System;
using System.IO;
using Windows.Foundation;
using Windows.Media.MediaProperties;
using Windows.Media.Transcoding;
using Windows.Storage.Streams;
And the MemoryRandomAccessStream
is just an implementation of the IRandomAccesStream
interface and can be found here.