2013-10-17 61 views
0

我的任务是使用NAudio和Lame将wma音频流转换为mp3流。下面的代码与文件名工作正常,但我希望它与内存流完成。我在NAudio搜索没有读取WMA音频流的方法。 NAudio可以吗?wma音频流使用NAudio c#mp3流式编码#

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

当前WMAFileReader类不支持从流中读取数据。 WMA API支持从IStream读取WMA,所以它绝对有可能。

如果您想自己实现流式传输,您需要从CodePlex获取WmaFileReaderWmaStream的源代码,并将它们用作修改后的类的模板。

您需要的第一件事是提供COM IStream接口到.NET 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实例实例 - MemoryStreamFileStream等。Stream实例需要可读和可搜索。

我试过上面的几个随机WMA文件,我在我的电脑上找到,加载到MemoryStream或使用FileStream,它的工作原理与我预期的一样。

大概Mark正在把这个功能添加到NAudio.Wma包中,所以考虑这个临时修复,直到NAudio支持它。

+0

我会试试这段代码。 –

0

使用NAudio将WMA转换为MP3最简单的方法是使用基于媒体基础的类。如果您使用的是Windows 8或更高版本,则应提供MP3编码器。

using (var reader = new MediaFoundationReader("test.wma")) 
{ 
    MediaFoundationEncoder.EncodeToMp3(reader, "test.mp3"); 
} 

在没有MP3编码器的系统上,我倾向于使用LAME.exe并通过stdin流式输入音频。有关此方法的更多信息,请参阅my article here