kekyo/FlashCap

Capture works first time on Linux, but not subsequent times

Muny opened this issue · 4 comments

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:

if (ioctl(this.fd, Interop.VIDIOC_DQBUF, buffer) < 0)

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.

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

@Muny Could you try to the branch develop top?

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

if ((buffer.flags & Interop.V4L2_BUF_FLAG_ERROR) != Interop.V4L2_BUF_FLAG_ERROR)

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.

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

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