kekyo / FlashCap

Independent video frame capture library on .NET/.NET Core and .NET Framework.
Apache License 2.0
203 stars 29 forks source link

Capture works first time on Linux, but not subsequent times #134

Closed Muny closed 7 months ago

Muny commented 9 months ago

Was working on #133 and ran into an issue.

With a fresh main branch, I run the FlashCap.OneShot sample successfully:

cat ➜  net8.0 git:(main) ✗ ./FlashCap.OneShot
Selected capture device: USB3.0 UHD: USB3.0 UHD: usb-0000:00:14.0-1: uvcvideo, Characteristics=55, 1920x1080 [YUYV, 60.000fps]
Captured 6220854 bytes.
The image wrote to file oneshot.bmp.

However, after subsequent attempts to run the sample, it crashes at the YUV trancoder:

cat ➜  net8.0 git:(main) ✗ ./FlashCap.OneShot
Selected capture device: USB3.0 UHD: USB3.0 UHD: usb-0000:00:14.0-1: uvcvideo, Characteristics=55, 1920x1080 [YUYV, 60.000fps]
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at FlashCap.Internal.BitmapTranscoder+<>c__DisplayClass1_0.<TranscodeFromYUVInternal>b__0(Int32)
   at System.Threading.Tasks.Parallel+<>c__DisplayClass19_0`2[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<ForWorker>b__1(System.Threading.Tasks.RangeWorker ByRef, Int64, Boolean ByRef)
   at System.Threading.Tasks.TaskReplicator+Replica.Execute()
   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.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()
[1]    18403 abort (core dumped)  ./FlashCap.OneShot

The only way to let it work again is to unplug my UVC device, then plug it back in. It then works for 1 frame, and no more.

After a little digging, I discovered that after here: https://github.com/kekyo/FlashCap/blob/854186a445e494548480ae0d6b607c1bf009eb57/FlashCap.Core/Devices/V4L2Device.cs#L306 The value of buffer.bytesused is 0.

image

If I change (int)buffer.bytesused to (int)buffer.length (which are the same value, except for when bytesused is 0) in the call to this.frameProcessor.OnFrameArrived, I can successfully capture multiple times.

It's not immediately clear to me what could be causing this. I don't know what the difference between bytesused and length is.

Muny commented 9 months ago

Just tried the Avalonia sample, and it behaves the same.

kekyo commented 9 months ago

@Muny Could you try to the branch develop top?

Maybe related, I fixed checking of received frame state flag in V4L2:

https://github.com/kekyo/FlashCap/blob/ef5462e1fcd513050fdb181a33dc8ae8331ade6d/FlashCap.Core/Devices/V4L2Device.cs#L410

If I change (int)buffer.bytesused to (int)buffer.length (which are the same value, except for when bytesused is 0) in the call to this.frameProcessor.OnFrameArrived, I can successfully capture multiple times.

I did this fix at first too, but it uses the incorrect size for variable frame sizes like MJPEG.

Muny commented 9 months ago

The changes in the develop branch do indeed fix this issue. 🥳

kekyo commented 7 months ago

I will close this issue as the fix will be reflected in the next release. Thanks.