问题描述
我正在制作一个可以预览波形的 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 对象的同一线程访问。