Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not capturing an Image #1

Open
Krutonium opened this issue Sep 24, 2020 · 5 comments
Open

Not capturing an Image #1

Krutonium opened this issue Sep 24, 2020 · 5 comments

Comments

@Krutonium
Copy link

So to begin with, here is my code:

using System;
using System.Collections.Generic;
using Iot.Device.Media;

namespace FaceMod
{
    class Program
    {
        static void Main(string[] args)
        {
            VideoConnectionSettings settings = new VideoConnectionSettings(busId: 0)
            {
                CaptureSize = (640, 480), ExposureType = ExposureType.Auto, PixelFormat = PixelFormat.MJPEG
            };
            using VideoDevice device = VideoDevice.Create(settings);
            IEnumerable<PixelFormat> formats = device.GetSupportedPixelFormats();
            foreach (var f in formats)
            {
                Console.WriteLine(f);
            }
            IEnumerable<(uint Width, uint Height)> resolutions = device.GetPixelFormatResolutions(PixelFormat.YUYV);
            foreach (var res in resolutions)
            {
                Console.WriteLine(res.Width + "x" + res.Height);
            }
            //Manually Verified that all settings are valid and my webcam is capable. Or at least claims to be.
            var cap = device.Capture();
            Console.WriteLine(cap.Length);
            //cap.Length is 0 - Nothing is ever captured.
            Console.ReadKey();
            
        } 
    }
}

The problem I am having is that I cannot get it to capture an image - Writing it to disk directly with the built in writes a 0 byte file, and the MemoryStream is always empty. I know that it does at least get as far as turning on the webcam, because it does manage to do that. It just never captures an image.

Any ideas?

@Krutonium
Copy link
Author

I went so far as to loop through every possible format and resolution, but no results.

           while (true)
            {
                foreach (var f in formats)
                {
                    foreach (var res in resolutions)
                    {
                        device.Settings.PixelFormat = f;
                        device.Settings.CaptureSize = res;
                        var cap = device.Capture();
                        Console.WriteLine(cap.Length);
                        
                    }
                }
            }

@lmoe
Copy link

lmoe commented Jan 7, 2021

Hey @Krutonium, have you found a solution yet?

I'm currently debating between OpenCV.Net and V4L2. I rather would use V4L2 because it has almost no dependency to anything. And OpenCV is also just using V4L2 at the end.

I took this day to look into the Issue and found an explanation.

The native calls mostly fail silently and are not handled. The calls are failing because the library is using invalid ioctl arguments.

@ZhangGaoxing

First of all, thanks for your library. It is exactly what I need. Let's make it work for all of us :)

The VideoSettings enum that contains all arguments seem to be dependent on platform, architecture, and maybe other factors. These arguments are not constant/static!

The enum is defining VIDIOC_S_FMT = -1060350459, however its -1060088315 on my system.

This results in "argument invalid" errors.

What you did a few lines deeper inside RawVideoSettings is a good approach, this is exactly how V4L2 is doing it.

However, some structs like v4l2_buffer, v4l2_format differ from the C headers. Other structs are fine, so the approach is correct.
(v4l2_format in particular seems to be way off. The size is almost twice than in C. I haven't found the reason yet.)

Therefore sizeof(struct v4l2_format) in C is not equal to Marshal.SizeOf<v4l2_format>(); in C#

Resulting again in wrong numbers.

For a quick test I have created a stub with a fixed size of 208 (like in C)

[StructLayout(LayoutKind.Sequential, Size = 208)]
public struct v4l2_format_aligned
{
}

public static int VIDIOC_S_FMT = Interop._IOWR('V', 5, typeof(v4l2_format_aligned));

-1060088315

That does seem to work, it calculates the same ioctl number like in C.

By using these numbers the ioctl calls seem to exit successfully, resulting in a clear image :)

I think the cleanest way to make it work is to remove the VideoSettings enum, fix all non matching v4l2 structures, use your already existing _IOR/_IORW functions to calculate the right argument values, and make more use of the capability response to check if certain calls are even possible.

@Krutonium
Copy link
Author

I have not.

@lmoe
Copy link

lmoe commented Jan 8, 2021

Okay.

So this is a working example, at least for me. You can try it out. https://github.com/lmoe/v4l2.net

Still WIP and requires some clean up.

@timblaer
Copy link

timblaer commented Jan 8, 2022

Hi, @Krutonium, I was digging down to how V4L2 works, and noticed that there is EAGAIN error possible for VIDIOC_DQBUF operation (meaning that buffer is not yet ready to be grabbed). I did multiple tests and never got the error that you did, so I thought, maybe EAGAIN is the error.

To test it out, debug through UnixVideoDevice.V4l2Struct method (when called from GetFrameData method). EAGAIN's int value is 112.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants