我的任务是使用NAudio和Lame将wma音频流转换为mp3流。下面的代码与文件名工作正常,但我希望它与内存流完成。我在NAudio搜索没有读取wma音频流的方法。 NAudio有可能吗?
public static byte[] ConvertWmaToMp3(uint bitrate = 128)
{
FileStream fs = new FileStream("..\\sample.wma", FileMode.Open, FileAccess.Read);
var ws = new NAudio.WindowsMediaFormat.WMAFileReader(fs.Name);
// Setup encoder configuration
WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(ws.WaveFormat.SampleRate, 16, ws.WaveFormat.Channels);
Yeti.Lame.BE_CONFIG beconf = new Yeti.Lame.BE_CONFIG(fmt, bitrate);
// Encode WAV to MP3
int blen = ws.WaveFormat.AverageBytesPerSecond;
byte[] buffer = new byte[blen];
byte[] mp3data = null;
using (MemoryStream mp3strm = new MemoryStream())
using (Mp3Writer mp3wri = new Mp3Writer(mp3strm, fmt, beconf))
{
int rc;
while ((rc = ws.Read(buffer, 0, blen)) > 0)
{
mp3wri.Write(buffer, 0, rc);
}
mp3data = mp3strm.ToArray();
}
return mp3data;
}
答案 0 :(得分:0)
目前WMAFileReader
类不支持从流中读取数据。 WMA API支持从IStream
读取WMA,因此绝对可以。
如果您想自己实现流式传输,则需要从CodePlex获取WmaFileReader
和WmaStream
的源代码,并将其用作修改后的类的模板。
您首先需要的是一个包装类,它为.NET IStream
提供COM Stream
接口。这是一个简单的:
public class InteropStream : IStream, IDisposable
{
public readonly Stream intern;
public InteropStream(Stream strm)
{
intern = strm;
}
~InteropStream()
{
Dispose(true);
}
public void Dispose()
{
Dispose(false);
}
protected void Dispose(bool final)
{
if (final)
intern.Dispose();
}
#region IStream Members
public void Clone(out IStream ppstm)
{
ppstm = null;
}
public void Commit(int grfCommitFlags)
{
intern.Flush();
}
readonly byte[] buffer = new byte[4096];
public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
{
if (pcbRead != IntPtr.Zero)
Marshal.WriteInt32(pcbRead, 0);
if (pcbWritten != IntPtr.Zero)
Marshal.WriteInt32(pcbWritten, 0);
}
public void LockRegion(long libOffset, long cb, int dwLockType)
{ }
public void Read(byte[] pv, int cb, IntPtr pcbRead)
{
int rc = intern.Read(pv, 0, cb);
if (pcbRead != IntPtr.Zero)
Marshal.WriteInt32(pcbRead, rc);
}
public void Revert()
{ }
public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
{
long origin = 0;
if (dwOrigin == 1) // STREAM_SEEK_CUR
origin = intern.Position;
else if (dwOrigin == 2) // STREAM_SEEK_END
origin = intern.Length;
long pos = origin + dlibMove;
intern.Position = pos;
if (plibNewPosition != IntPtr.Zero)
Marshal.WriteInt64(plibNewPosition, pos);
}
public void SetSize(long libNewSize)
{ }
public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
{
var res = new System.Runtime.InteropServices.ComTypes.STATSTG();
res.type = 2; // STGTY_STREAM
res.cbSize = intern.Length;
pstatstg = res;
}
public void UnlockRegion(long libOffset, long cb, int dwLockType)
{ }
public void Write(byte[] pv, int cb, IntPtr pcbWritten)
{ }
#endregion
}
接下来将WmaStream
代码复制到项目中的新命名空间,并将以下代码添加到类的顶部:
InteropStream interopStrm = null;
public WmaStream(Stream fileStream)
: this(fileStream, null)
{ }
public WmaStream(Stream fileStream, WaveFormat OutputFormat)
{
interopStrm = new InteropStream(fileStream);
m_reader = WM.CreateSyncReader(WMT_RIGHTS.WMT_RIGHT_NO_DRM);
try
{
IWMSyncReader2 rdr = m_reader as IWMSyncReader2;
rdr.OpenStream(interopStrm);
Init(OutputFormat);
}
catch
{
try
{
m_reader.Close();
}
catch
{
}
m_reader = null;
throw;
}
}
对WmaFileReader
和以下代码执行相同操作:
public WMAFileReader(Stream wmaStream)
{
m_wmaStream = new WmaStream2(wmaStream);
m_waveFormat = m_wmaStream.Format;
}
现在,您可以使用文件名或WmaFileReader
实例 - Stream
,MemoryStream
等创建已修改FileStream
的实例。Stream
实例需要具有可读性和可搜索性。
我已经在我的计算机上找到的一些随机WMA文件上尝试了上述操作,加载到MemoryStream
或使用FileStream
,并且它按预期工作。
据推测,Mark正在努力将此功能添加到NAudio.Wma包中,因此在NAudio支持之前,请考虑这是一个临时修复。
答案 1 :(得分:0)
使用NAudio将WMA转换为MP3的最简单方法是使用基于Media Foundation的类。如果您使用的是Windows 8及以上版本,则应提供MP3编码器。
using (var reader = new MediaFoundationReader("test.wma"))
{
MediaFoundationEncoder.EncodeToMp3(reader, "test.mp3");
}
在没有MP3编码器的系统上,我倾向于使用LAME.exe并通过stdin传输输入音频。有关此方法的详细信息,请参阅my article here。