Naudio Read 在读取 mp4 时抛出 InvalidCast 异常,但并非总是如此为什么?

问题描述

我正在制作一个可以预览波形的 Windows 窗体。 我在以下使用 AudioFileReader.Read:
A...当我第一次加载文件并通读以保存峰值文件以进行缩放预览时
B...当我计算整个音频的 FFT
C...当我绘制波形

wav/mp3 工作正常,但是当我加载 mp4 时,A 和 B 中的读取工作正常,但 C 抛出 system.invalidCastException。
为什么它只发生在 C 中?

异常和代码如下。谢谢。

异常:

例外がスローされました: 'system.invalidCastException' (NAudio.dll の中)
system.invalidCastException: 型 'System.__ComObject' の COM オブジェクトをインターフェイス型 'NAudio.MediaFoundation.IMFSourceReader' にキャストできません。IID '{70AE66F2-C809-4E4F-8915-BDCB406B7993}' が指定されたインターフェイスの COM コンポーネント上での QueryInterface 呼び出しのときに次のエラーが発生したため、この操作に失敗しました: インターフェイスがサポートされていません (HRESULT からの例外:0x80004002 (E_NOINTERFACE))。
   場所 System.StubHelpers.StubHelpers.GetCOMIPFromrCW(Object objSrc,IntPtr pCPCMD,IntPtr& ppTarget,Boolean& pfNeedsRelease)
   場所 NAudio.MediaFoundation.IMFSourceReader.SetCurrentPosition(Guid guidTimeFormat,IntPtr varPosition)
   場所 NAudio.Wave.MediaFoundationReader.Reposition(Int64 desiredPosition)
   場所 NAudio.Wave.MediaFoundationReader.Read(Byte[] buffer,Int32 offset,Int32 count)
   場所 NAudio.Wave.SampleProviders.Pcm16BitToSampleProvider.Read(Single[] buffer,Int32 count)
   場所 NAudio.Wave.SampleProviders.MeteringSampleProvider.Read(Single[] buffer,Int32 count)
   場所 NAudio.Wave.SampleProviders.VolumeSampleProvider.Read(Single[] buffer,Int32 sampleCount)
   場所 NAudio.Wave.AudioFileReader.Read(Single[] buffer,Int32 count)
   場所 SengiriWave.soundStream.GetNextPeak(Int32 id,Int64 samplesperpeak,Boolean withrms) 場所 D:\VisualStudio\SengiriWave\SoundStream.cs:行 303
   場所 SengiriWave.DrawWave.PaintPeaksLines(SoundStream sound,Graphics graphics,Int32 skippx,Boolean withRMS) 場所 D:\VisualStudio\SengiriWave\DrawWave.cs:行 105
   場所 SengiriWave.MainWindow.wave_Paint(Object sender,PaintEventArgs e) 場所 D:\VisualStudio\SengiriWave\MainWindow - wave.cs:行 194

代码:(已编辑;简化以方便复制粘贴)

public partial class Form1 : Form
    {
        List<AudioFileReader> streams = new List<AudioFileReader>();
        int ch;
        long fullsamples;
        WaveFormat waveformat;
        long fullms;
        int block = 128;
        int fftLength = 128;

        public Form1()
        {
            InitializeComponent();

            streams.Add(new AudioFileReader(/*Media file path*/));
            ch = streams[0].WaveFormat.Channels;
            fullsamples = (int)(streams[0].Length / streams[0].BlockAlign);
            waveformat = streams[0].WaveFormat;
            fullms = (int)(fullsamples * 1000 / waveformat.SampleRate);

            backgroundWorker1.RunWorkerAsync();
        }

        //A
        private void backgroundWorker1_DoWork(object sender,DoWorkEventArgs e)
        {
            BackgroundWorker control = (BackgroundWorker)sender;

            float[] write = new float[ch * 2];

            int block = this.block * 2;
            float[] sample = new float[block * ch];

            for (int x = 0; x < 3; x++)
            {
                var writer = new WaveFileWriter("tempshrink" + x + ".wav",streams[x].WaveFormat);
                streams[x].Position = 0;

                int read = streams[x].Read(sample,block * ch);
                while (read != 0)
                {
                    for (int b = 0; b < block; b++)
                    {
                        for (int c = 0; c < ch; c++)
                        {
                            int sampleindex = b * ch + c;
                            if (b == 0)
                            {
                                write[c] = sample[sampleindex];
                                write[c + ch] = sample[sampleindex];
                            }
                            else
                            {
                                write[c] = Math.Max(write[c],sample[sampleindex]);
                                write[c + ch] = Math.Min(write[c + ch],sample[sampleindex]);
                            }
                        }
                    }
                    //書き込み
                    for (int i = 0; i < write.Length; i++) writer.WriteSample(write[i]);

                    read = streams[x].Read(sample,block * ch);
                }
                writer.dispose();
                streams.Add(new AudioFileReader("tempshrink" + x + ".wav"));
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
        {
            backgroundWorker2.RunWorkerAsync();
        }

        //B
        private void backgroundWorker2_DoWork(object sender,DoWorkEventArgs e)
        {
            BackgroundWorker control = (BackgroundWorker)sender;

            AudioFileReader reader = streams[0];
            reader.Position = 0;

            int yoko = (int)(fullsamples / fftLength);
            int tate = fftLength / 2;
            int stride = (yoko % 4 == 0) ? yoko : (yoko / 4 + 1) * 4;
            byte[] result = new byte[stride * tate];
            byte[][] spec = new byte[yoko][];
            int m = (int)Math.Log(fftLength,2);
            int bundle = 10;
            Complex[] buffer = new Complex[fftLength];
            int count = 0;

            int readoncelength = fftLength * ch * bundle;
            float[] sample = new float[readoncelength];

            while (reader.Read(sample,readoncelength) != 0)
            {
                for (int i = 0; i < bundle; i++)
                {
                    int timex = count * bundle + i;
                    if (timex >= yoko) break;
                    for (int r = 0; r < fftLength; r++)
                    {
                        int index = (i * fftLength + r) * ch;
                        if (ch == 2) sample[index] = (sample[index] + sample[index + 1]) / 2;

                        buffer[r].X = sample[index] * (float)FastFourierTransform.HammingWindow(r,fftLength);
                        buffer[r].Y = 0.0f;
                    }

                    FastFourierTransform.FFT(true,m,buffer);

                    spec[timex] = new byte[tate];

                    for (int k = 0; k < tate; k++)
                    {
                        double diagonal = Math.Sqrt(buffer[k].X * buffer[k].X + buffer[k].Y * buffer[k].Y);
                        double intensityDB = 10.0 * Math.Log10(diagonal);

                        const double minDB = -50.0;
                        double percent = (intensityDB < minDB) ? 1.0 : intensityDB / minDB;

                        result[timex + (tate - 1 - k) * stride] = (byte)(255f * percent / 16);
                        spec[timex][k] = (byte)(255f * percent);
                    }
                }

                count++;
            }

            e.Result = result;
        }

        private void backgroundWorker2_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
        {
            timer1.Enabled = true;
        }

        //
        private void timer1_Tick(object sender,EventArgs e)
        {
            float[] samples = new float[2];

            //Throws Exception Here
            while (streams[0].Read(samples,2)!=0)
            {

            }
        }
    }

解决方法

很可能是因为您从不同的线程访问它。 NAudio 调用的底层 API 需要从创建 COM 对象的同一线程访问。