AddictedCS / soundfingerprinting

Open source audio fingerprinting in .NET. An efficient algorithm for acoustic fingerprinting written purely in C#.
https://emysound.com
MIT License
946 stars 189 forks source link

Access Violation crash - repeatable with file #192

Closed cjmanca closed 2 years ago

cjmanca commented 2 years ago

While audio fingerprinting a file via ffmpeg, I receive an access violation:

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at SoundFingerprinting.Emy.FFmpeg.Audio.AudioConverter.ConvertAndStore(FFmpeg.AutoGen.AVFrame*)
   at SoundFingerprinting.Emy.FFmpeg.Audio.AudioConverter.Convert(FFmpeg.AutoGen.AVFrame*)
   at SoundFingerprinting.Emy.FFmpeg.Decoder.Decode(FFmpeg.AutoGen.AVPacket*)
   at SoundFingerprinting.Emy.FFmpeg.Demuxer.Demux(Double)
   at SoundFingerprinting.Emy.AudioVideo.Data.FFmpegDataService+<ReadAVTrack>d__4.MoveNext()
   at System.Collections.Generic.List`1[[System.__Canon, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]..ctor(System.Collections.Generic.IEnumerable`1<System.__Canon>)
   at System.Linq.Enumerable.ToList[[System.__Canon, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Collections.Generic.IEnumerable`1<System.__Canon>)
   at SoundFingerprinting.Emy.AudioVideo.Data.FFmpegDataService.ReadTrack(System.String, SoundFingerprinting.Data.MediaType, Double, SoundFingerprinting.Media.AVTrackReadConfiguration)
   at SoundFingerprinting.Emy.FFmpegAudioService.ReadAVTrackFromFile(System.String, SoundFingerprinting.Media.AVTrackReadConfiguration, Double, Double, SoundFingerprinting.Data.MediaType)
   at SoundFingerprinting.Emy.FFmpegAudioService.GetAudioTrack(System.String, Int32, Double)
   at SoundFingerprinting.Emy.FFmpegAudioService.ReadMonoSamplesFromFile(System.String, Int32, Double, Double)
   at SoundFingerprinting.Command.FingerprintCommand+<>c__DisplayClass13_0.<From>b__0()
   at System.Threading.Tasks.Task`1[[System.__Canon, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread)
   at System.Threading.Tasks.Task.ExecuteFromThreadPool(System.Threading.Thread)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()
   at System.Threading.Thread.StartCallback()

This happens every time with this file: https://we.tl/t-RymrJksWq9

I'm sure it's an issue with that file, and I don't expect it to work with the library, however I would like it to throw an exception gracefully that I can catch, rather than hard crashing with an uncatchable accessviolation.

AddictedCS commented 2 years ago

AccessViolationException is thrown by the underlying native FFmpeg library. These types of exceptions can't be caught as per design docs:

Starting with .NET Framework 4, AccessViolationException exceptions thrown by the common language runtime are not handled by the catch statement in a structured exception handler if the exception occurs outside of the memory reserved by the common language runtime

A similar problem has been reported in #189, and there is no definitive answer to why specific files generate this issue. Most probably, it is related to an encoding issue. As of now, you can try to re-encode the file with the same ffmpeg that is running on the host machine executing your application before passing it to the library:

ffmpeg -i <path to file> file.mkv
AddictedCS commented 2 years ago

BTW this particular file didn't generate any issues with the following FFmpeg installed on the host machine:

ffmpeg version 4.4.1 Copyright (c) 2000-2021 the FFmpeg developers
  built with Apple clang version 13.0.0 (clang-1300.0.29.3)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.4.1_5 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-avresample --enable-videotoolbox
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
cjmanca commented 2 years ago

Hmm, interesting. I'm using the recommended ffmpeg for windows. It's probably because that's an older version than current I guess, but current throws errors when attempting to use with the library on Windows.

ffmpeg version 4.4.1-full_build-www.gyan.dev Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 11.2.0 (Rev1, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-shared --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil      56. 70.100 / 56. 70.100
libavcodec     58.134.100 / 58.134.100
libavformat    58. 76.100 / 58. 76.100
libavdevice    58. 13.100 / 58. 13.100
libavfilter     7.110.100 /  7.110.100
libswscale      5.  9.100 /  5.  9.100
libswresample   3.  9.100 /  3.  9.100
libpostproc    55.  9.100 / 55.  9.100
cjmanca commented 2 years ago

As of now, you can try to re-encode the file with the same ffmpeg that is running on the host machine executing your application before passing it to the library:

Yeah, and I have done that manually for the couple of files so far that I've encountered with the issue, but since 99.99% of the files I've encountered don't have the error, I'd rather not re-encode every file just in case. This tool is intended to run passively in the background unmonitored. If I could catch the exception, then I could re-encode as needed, but since I can't, I'm at a bit of a loss for how to handle it.

cjmanca commented 2 years ago

Oh! Is the engine converting/reencoding the audio before/while opening it? And if so - is there a format that it wouldn't have to reencode? If so - I could force encode to that all the time and it shouldn't be any slower than right now, since it would just change at what point it's converting it.

AddictedCS commented 2 years ago

Yes, the engine is converting the audio to 5512Hz, mono. You could try converting it to this format, and it should not incur a performance penalty except for codec decoding, which should be negligible.

cjmanca commented 2 years ago

Great, thanks, I'm force encoding all files to that and it seems to be working well. No more exceptions since!

Is there a similar thing for video fingerprinting, where I could convert a video to a specific resolution with specific filters so that the fingerprinting doesn't need to process it?