0

私の仕事は、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;                      

    }
4

2 に答える 2

0

現在、WMAFileReaderクラスはストリームからのデータの読み取りをサポートしていません。WMA API は からの WMA の読み取りをサポートしているIStreamため、確実に可能です。

ストリーミングを自分で実装したい場合は、CodePlex のソース コードを入手して、変更したクラスのテンプレートとして使用する必要がありWmaFileReaderますWmaStream

最初に必要なのはIStream、.NET への 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 がサポートするまで、これは暫定的な修正と考えてください。

于 2013-10-19T07:15:02.323 に答える