[libcamera-devel] Add option to list displays
diff mbox series

Message ID 20211027100441.18248-1-ecurtin@redhat.com
State Superseded
Headers show
Series
  • [libcamera-devel] Add option to list displays
Related show

Commit Message

Eric Curtin Oct. 27, 2021, 10:04 a.m. UTC
xrand --query isn't always available and does not always display all
conneted connectors.

Signed-off-by: Eric Curtin <ecurtin@redhat.com>
---
 src/cam/main.cpp | 31 ++++++++++++++++++++++++++-----
 src/cam/main.h   |  3 +++
 2 files changed, 29 insertions(+), 5 deletions(-)

Comments

Umang Jain Oct. 27, 2021, 6:23 p.m. UTC | #1
Hi Eric,

Thank you for the patch.

On 10/27/21 3:34 PM, Eric Curtin wrote:
> xrand --query isn't always available and does not always display all
> conneted connectors.

s/conneted/connected/

I believe commit message can be a little bit more descriptive providing 
some context around xrand --query.

Also a comment on the subject, it should be prefixed with `cam: `

     cam: Add option to list displays


>
> Signed-off-by: Eric Curtin <ecurtin@redhat.com>
> ---
>   src/cam/main.cpp | 31 ++++++++++++++++++++++++++-----
>   src/cam/main.h   |  3 +++
>   2 files changed, 29 insertions(+), 5 deletions(-)
>
> diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> index c7f664b9..319cbf4d 100644
> --- a/src/cam/main.cpp
> +++ b/src/cam/main.cpp
> @@ -15,6 +15,11 @@
>   #include <libcamera/property_ids.h>
>   
>   #include "camera_session.h"
> +
> +#ifdef HAVE_KMS
> +#include "drm.h"
> +#endif
> +
>   #include "event_loop.h"
>   #include "main.h"
>   #include "options.h"
> @@ -137,6 +142,7 @@ int CamApp::parseOptions(int argc, char *argv[])
>   			 "Display viewfinder through DRM/KMS on specified connector",
>   			 "display", ArgumentOptional, "connector", false,
>   			 OptCamera);
> +	parser.addOption(OptListDisplays, OptionNone, "List all displays", "list-displays");


Can there are displays with status ::Disconnected or ::Unknown, I am not 
sure. If yes, I would reword the description to

         "List all connected displays"

(just a suggestion, if it makes sense to you)

>   #endif
>   	parser.addOption(OptFile, OptionString,
>   			 "Write captured frames to disk\n"
> @@ -202,7 +208,22 @@ int CamApp::run()
>   		}
>   	}
>   
> -	/* 2. Create the camera sessions. */
> +#ifdef HAVE_KMS
> +	/* 2. List all displays. */
> +	if (options_.isSet(OptListDisplays)) {
> +		std::cout << "Available displays:" << std::endl;
> +
> +		DRM::Device dev;
> +		dev.init();


This returns an integer value which should be checked.

> +		for (const DRM::Connector &conn : dev.connectors()) {
> +			if (conn.status() == DRM::Connector::Connected) {
> +				std::cout << conn.name() << std::endl;


I wonder if we should also print the type (conn.type()) along with the 
connector name.

The patch looks to me overall.

> +			}
> +		}
> +	}
> +#endif
> +
> +	/* 3. Create the camera sessions. */
>   	std::vector<std::unique_ptr<CameraSession>> sessions;
>   
>   	if (options_.isSet(OptCamera)) {
> @@ -229,7 +250,7 @@ int CamApp::run()
>   		}
>   	}
>   
> -	/* 3. Print camera information. */
> +	/* 4. Print camera information. */
>   	if (options_.isSet(OptListControls) ||
>   	    options_.isSet(OptListProperties) ||
>   	    options_.isSet(OptInfo)) {
> @@ -243,7 +264,7 @@ int CamApp::run()
>   		}
>   	}
>   
> -	/* 4. Start capture. */
> +	/* 5. Start capture. */
>   	for (const auto &session : sessions) {
>   		if (!session->options().isSet(OptCapture))
>   			continue;
> @@ -257,7 +278,7 @@ int CamApp::run()
>   		loopUsers_++;
>   	}
>   
> -	/* 5. Enable hotplug monitoring. */
> +	/* 6. Enable hotplug monitoring. */
>   	if (options_.isSet(OptMonitor)) {
>   		std::cout << "Monitoring new hotplug and unplug events" << std::endl;
>   		std::cout << "Press Ctrl-C to interrupt" << std::endl;
> @@ -271,7 +292,7 @@ int CamApp::run()
>   	if (loopUsers_)
>   		loop_.exec();
>   
> -	/* 6. Stop capture. */
> +	/* 7. Stop capture. */
>   	for (const auto &session : sessions) {
>   		if (!session->options().isSet(OptCapture))
>   			continue;
> diff --git a/src/cam/main.h b/src/cam/main.h
> index 1c2fab76..72050d27 100644
> --- a/src/cam/main.h
> +++ b/src/cam/main.h
> @@ -21,6 +21,9 @@ enum {
>   	OptListControls = 256,
>   	OptStrictFormats = 257,
>   	OptMetadata = 258,
> +#ifdef HAVE_KMS
> +	OptListDisplays = 259
> +#endif
>   };
>   
>   #endif /* __CAM_MAIN_H__ */
Laurent Pinchart Oct. 27, 2021, 9:12 p.m. UTC | #2
Hi Eric,

Thank you for the patch.

On Wed, Oct 27, 2021 at 11:04:41AM +0100, Eric Curtin wrote:
> xrand --query isn't always available and does not always display all
> conneted connectors.

Stupid questions, couldn't connectors also be listed through sysfs ?

for conn in /sys/class/drm/card*-* ; do status=$(cat $conn/status) ; if [ $status == connected ] ; then echo $conn ; fi ; done

I'm not opposed to adding this feature to the cam application, but I
wonder if it really belongs here, especially if we consider that a next
step would be to print supported modes.

> Signed-off-by: Eric Curtin <ecurtin@redhat.com>
> ---
>  src/cam/main.cpp | 31 ++++++++++++++++++++++++++-----
>  src/cam/main.h   |  3 +++
>  2 files changed, 29 insertions(+), 5 deletions(-)
> 
> diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> index c7f664b9..319cbf4d 100644
> --- a/src/cam/main.cpp
> +++ b/src/cam/main.cpp
> @@ -15,6 +15,11 @@
>  #include <libcamera/property_ids.h>
>  
>  #include "camera_session.h"
> +
> +#ifdef HAVE_KMS
> +#include "drm.h"
> +#endif
> +
>  #include "event_loop.h"
>  #include "main.h"
>  #include "options.h"
> @@ -137,6 +142,7 @@ int CamApp::parseOptions(int argc, char *argv[])
>  			 "Display viewfinder through DRM/KMS on specified connector",
>  			 "display", ArgumentOptional, "connector", false,
>  			 OptCamera);
> +	parser.addOption(OptListDisplays, OptionNone, "List all displays", "list-displays");
>  #endif
>  	parser.addOption(OptFile, OptionString,
>  			 "Write captured frames to disk\n"
> @@ -202,7 +208,22 @@ int CamApp::run()
>  		}
>  	}
>  
> -	/* 2. Create the camera sessions. */
> +#ifdef HAVE_KMS
> +	/* 2. List all displays. */
> +	if (options_.isSet(OptListDisplays)) {
> +		std::cout << "Available displays:" << std::endl;
> +
> +		DRM::Device dev;
> +		dev.init();

As Umang mentioned, errors should be checked.

> +		for (const DRM::Connector &conn : dev.connectors()) {
> +			if (conn.status() == DRM::Connector::Connected) {
> +				std::cout << conn.name() << std::endl;
> +			}

No need for curly braces in the inner if.

> +		}
> +	}
> +#endif
> +
> +	/* 3. Create the camera sessions. */
>  	std::vector<std::unique_ptr<CameraSession>> sessions;
>  
>  	if (options_.isSet(OptCamera)) {
> @@ -229,7 +250,7 @@ int CamApp::run()
>  		}
>  	}
>  
> -	/* 3. Print camera information. */
> +	/* 4. Print camera information. */
>  	if (options_.isSet(OptListControls) ||
>  	    options_.isSet(OptListProperties) ||
>  	    options_.isSet(OptInfo)) {
> @@ -243,7 +264,7 @@ int CamApp::run()
>  		}
>  	}
>  
> -	/* 4. Start capture. */
> +	/* 5. Start capture. */
>  	for (const auto &session : sessions) {
>  		if (!session->options().isSet(OptCapture))
>  			continue;
> @@ -257,7 +278,7 @@ int CamApp::run()
>  		loopUsers_++;
>  	}
>  
> -	/* 5. Enable hotplug monitoring. */
> +	/* 6. Enable hotplug monitoring. */
>  	if (options_.isSet(OptMonitor)) {
>  		std::cout << "Monitoring new hotplug and unplug events" << std::endl;
>  		std::cout << "Press Ctrl-C to interrupt" << std::endl;
> @@ -271,7 +292,7 @@ int CamApp::run()
>  	if (loopUsers_)
>  		loop_.exec();
>  
> -	/* 6. Stop capture. */
> +	/* 7. Stop capture. */
>  	for (const auto &session : sessions) {
>  		if (!session->options().isSet(OptCapture))
>  			continue;
> diff --git a/src/cam/main.h b/src/cam/main.h
> index 1c2fab76..72050d27 100644
> --- a/src/cam/main.h
> +++ b/src/cam/main.h
> @@ -21,6 +21,9 @@ enum {
>  	OptListControls = 256,
>  	OptStrictFormats = 257,
>  	OptMetadata = 258,
> +#ifdef HAVE_KMS
> +	OptListDisplays = 259
> +#endif
>  };
>  
>  #endif /* __CAM_MAIN_H__ */
Eric Curtin Oct. 28, 2021, 2:35 p.m. UTC | #3
Hi Umang,

On Wed, 27 Oct 2021 at 19:29, Umang Jain <umang.jain@ideasonboard.com> wrote:
>
> Hi Eric,
>
> Thank you for the patch.
>
> On 10/27/21 3:34 PM, Eric Curtin wrote:
> > xrand --query isn't always available and does not always display all
> > conneted connectors.
>
> s/conneted/connected/
>
> I believe commit message can be a little bit more descriptive providing
> some context around xrand --query.
>
> Also a comment on the subject, it should be prefixed with `cam: `
>
>      cam: Add option to list displays
>
>
> >
> > Signed-off-by: Eric Curtin <ecurtin@redhat.com>
> > ---
> >   src/cam/main.cpp | 31 ++++++++++++++++++++++++++-----
> >   src/cam/main.h   |  3 +++
> >   2 files changed, 29 insertions(+), 5 deletions(-)
> >
> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> > index c7f664b9..319cbf4d 100644
> > --- a/src/cam/main.cpp
> > +++ b/src/cam/main.cpp
> > @@ -15,6 +15,11 @@
> >   #include <libcamera/property_ids.h>
> >
> >   #include "camera_session.h"
> > +
> > +#ifdef HAVE_KMS
> > +#include "drm.h"
> > +#endif
> > +
> >   #include "event_loop.h"
> >   #include "main.h"
> >   #include "options.h"
> > @@ -137,6 +142,7 @@ int CamApp::parseOptions(int argc, char *argv[])
> >                        "Display viewfinder through DRM/KMS on specified connector",
> >                        "display", ArgumentOptional, "connector", false,
> >                        OptCamera);
> > +     parser.addOption(OptListDisplays, OptionNone, "List all displays", "list-displays");
>
>
> Can there are displays with status ::Disconnected or ::Unknown, I am not
> sure. If yes, I would reword the description to
>
>          "List all connected displays"
>
> (just a suggestion, if it makes sense to you)

You got me thinking, I might just list all displays connected, disconnected and
unknown. How many displays can there be? Might as well display all,
the user could
always filter via grep.

>
> >   #endif
> >       parser.addOption(OptFile, OptionString,
> >                        "Write captured frames to disk\n"
> > @@ -202,7 +208,22 @@ int CamApp::run()
> >               }
> >       }
> >
> > -     /* 2. Create the camera sessions. */
> > +#ifdef HAVE_KMS
> > +     /* 2. List all displays. */
> > +     if (options_.isSet(OptListDisplays)) {
> > +             std::cout << "Available displays:" << std::endl;
> > +
> > +             DRM::Device dev;
> > +             dev.init();
>
>
> This returns an integer value which should be checked.
>
> > +             for (const DRM::Connector &conn : dev.connectors()) {
> > +                     if (conn.status() == DRM::Connector::Connected) {
> > +                             std::cout << conn.name() << std::endl;
>
>
> I wonder if we should also print the type (conn.type()) along with the
> connector name.

The type is included in the name and deduced from this map, (interestingly
a "DP" type is often physically a HDMI port):

const std::map<uint32_t, const char *> connectorTypeNames{
{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
{ DRM_MODE_CONNECTOR_Composite, "Composite" },
{ DRM_MODE_CONNECTOR_SVIDEO, "S-Video" },
{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
{ DRM_MODE_CONNECTOR_Component, "Component" },
{ DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" },
{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
{ DRM_MODE_CONNECTOR_TV, "TV" },
{ DRM_MODE_CONNECTOR_eDP, "eDP" },
{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
{ DRM_MODE_CONNECTOR_DSI, "DSI" },
{ DRM_MODE_CONNECTOR_DPI, "DPI" },
};

>
> The patch looks to me overall.
>
> > +                     }
> > +             }
> > +     }
> > +#endif
> > +
> > +     /* 3. Create the camera sessions. */
> >       std::vector<std::unique_ptr<CameraSession>> sessions;
> >
> >       if (options_.isSet(OptCamera)) {
> > @@ -229,7 +250,7 @@ int CamApp::run()
> >               }
> >       }
> >
> > -     /* 3. Print camera information. */
> > +     /* 4. Print camera information. */
> >       if (options_.isSet(OptListControls) ||
> >           options_.isSet(OptListProperties) ||
> >           options_.isSet(OptInfo)) {
> > @@ -243,7 +264,7 @@ int CamApp::run()
> >               }
> >       }
> >
> > -     /* 4. Start capture. */
> > +     /* 5. Start capture. */
> >       for (const auto &session : sessions) {
> >               if (!session->options().isSet(OptCapture))
> >                       continue;
> > @@ -257,7 +278,7 @@ int CamApp::run()
> >               loopUsers_++;
> >       }
> >
> > -     /* 5. Enable hotplug monitoring. */
> > +     /* 6. Enable hotplug monitoring. */
> >       if (options_.isSet(OptMonitor)) {
> >               std::cout << "Monitoring new hotplug and unplug events" << std::endl;
> >               std::cout << "Press Ctrl-C to interrupt" << std::endl;
> > @@ -271,7 +292,7 @@ int CamApp::run()
> >       if (loopUsers_)
> >               loop_.exec();
> >
> > -     /* 6. Stop capture. */
> > +     /* 7. Stop capture. */
> >       for (const auto &session : sessions) {
> >               if (!session->options().isSet(OptCapture))
> >                       continue;
> > diff --git a/src/cam/main.h b/src/cam/main.h
> > index 1c2fab76..72050d27 100644
> > --- a/src/cam/main.h
> > +++ b/src/cam/main.h
> > @@ -21,6 +21,9 @@ enum {
> >       OptListControls = 256,
> >       OptStrictFormats = 257,
> >       OptMetadata = 258,
> > +#ifdef HAVE_KMS
> > +     OptListDisplays = 259
> > +#endif
> >   };
> >
> >   #endif /* __CAM_MAIN_H__ */
>

About to resend patch with yours and Laurents suggestions.

Is mise le meas/Regards,

Eric Curtin
Eric Curtin Oct. 28, 2021, 3:26 p.m. UTC | #4
Hi Laurent,

On Wed, 27 Oct 2021 at 22:13, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Eric,
>
> Thank you for the patch.
>
> On Wed, Oct 27, 2021 at 11:04:41AM +0100, Eric Curtin wrote:
> > xrand --query isn't always available and does not always display all
> > conneted connectors.
>
> Stupid questions, couldn't connectors also be listed through sysfs ?
>
> for conn in /sys/class/drm/card*-* ; do status=$(cat $conn/status) ; if [ $status == connected ] ; then echo $conn ; fi ; done
>
> I'm not opposed to adding this feature to the cam application, but I
> wonder if it really belongs here, especially if we consider that a next
> step would be to print supported modes.

Printing modes is where I was gonna do next. I only learned about
/sys/class/drm/card now
as a new guy to DRM, I think it would be useful for those who aren't
familiar with /sys
directory structure for drm. Finding documentation for this can be
hard and a tool is easier to maintain anyway.

Are you thinking maybe a separate binary called drm-info? (drm-utils
is a taken name by a
package that is seems not so useful in the context of the cam
application), etc? We list all
the equivalent cam information with the "cam -I -c1", it can be hard
to gather the equivalent
display info and if we can get them both at the same place, same
binary, would be nice!

>
> > Signed-off-by: Eric Curtin <ecurtin@redhat.com>
> > ---
> >  src/cam/main.cpp | 31 ++++++++++++++++++++++++++-----
> >  src/cam/main.h   |  3 +++
> >  2 files changed, 29 insertions(+), 5 deletions(-)
> >
> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> > index c7f664b9..319cbf4d 100644
> > --- a/src/cam/main.cpp
> > +++ b/src/cam/main.cpp
> > @@ -15,6 +15,11 @@
> >  #include <libcamera/property_ids.h>
> >
> >  #include "camera_session.h"
> > +
> > +#ifdef HAVE_KMS
> > +#include "drm.h"
> > +#endif
> > +
> >  #include "event_loop.h"
> >  #include "main.h"
> >  #include "options.h"
> > @@ -137,6 +142,7 @@ int CamApp::parseOptions(int argc, char *argv[])
> >                        "Display viewfinder through DRM/KMS on specified connector",
> >                        "display", ArgumentOptional, "connector", false,
> >                        OptCamera);
> > +     parser.addOption(OptListDisplays, OptionNone, "List all displays", "list-displays");
> >  #endif
> >       parser.addOption(OptFile, OptionString,
> >                        "Write captured frames to disk\n"
> > @@ -202,7 +208,22 @@ int CamApp::run()
> >               }
> >       }
> >
> > -     /* 2. Create the camera sessions. */
> > +#ifdef HAVE_KMS
> > +     /* 2. List all displays. */
> > +     if (options_.isSet(OptListDisplays)) {
> > +             std::cout << "Available displays:" << std::endl;
> > +
> > +             DRM::Device dev;
> > +             dev.init();
>
> As Umang mentioned, errors should be checked.
>
> > +             for (const DRM::Connector &conn : dev.connectors()) {
> > +                     if (conn.status() == DRM::Connector::Connected) {
> > +                             std::cout << conn.name() << std::endl;
> > +                     }
>
> No need for curly braces in the inner if.
>
> > +             }
> > +     }
> > +#endif
> > +
> > +     /* 3. Create the camera sessions. */
> >       std::vector<std::unique_ptr<CameraSession>> sessions;
> >
> >       if (options_.isSet(OptCamera)) {
> > @@ -229,7 +250,7 @@ int CamApp::run()
> >               }
> >       }
> >
> > -     /* 3. Print camera information. */
> > +     /* 4. Print camera information. */
> >       if (options_.isSet(OptListControls) ||
> >           options_.isSet(OptListProperties) ||
> >           options_.isSet(OptInfo)) {
> > @@ -243,7 +264,7 @@ int CamApp::run()
> >               }
> >       }
> >
> > -     /* 4. Start capture. */
> > +     /* 5. Start capture. */
> >       for (const auto &session : sessions) {
> >               if (!session->options().isSet(OptCapture))
> >                       continue;
> > @@ -257,7 +278,7 @@ int CamApp::run()
> >               loopUsers_++;
> >       }
> >
> > -     /* 5. Enable hotplug monitoring. */
> > +     /* 6. Enable hotplug monitoring. */
> >       if (options_.isSet(OptMonitor)) {
> >               std::cout << "Monitoring new hotplug and unplug events" << std::endl;
> >               std::cout << "Press Ctrl-C to interrupt" << std::endl;
> > @@ -271,7 +292,7 @@ int CamApp::run()
> >       if (loopUsers_)
> >               loop_.exec();
> >
> > -     /* 6. Stop capture. */
> > +     /* 7. Stop capture. */
> >       for (const auto &session : sessions) {
> >               if (!session->options().isSet(OptCapture))
> >                       continue;
> > diff --git a/src/cam/main.h b/src/cam/main.h
> > index 1c2fab76..72050d27 100644
> > --- a/src/cam/main.h
> > +++ b/src/cam/main.h
> > @@ -21,6 +21,9 @@ enum {
> >       OptListControls = 256,
> >       OptStrictFormats = 257,
> >       OptMetadata = 258,
> > +#ifdef HAVE_KMS
> > +     OptListDisplays = 259
> > +#endif
> >  };
> >
> >  #endif /* __CAM_MAIN_H__ */
>
> --
> Regards,
>
> Laurent Pinchart
>

Is mise le meas/Regards,

Eric Curtin
Kieran Bingham Oct. 28, 2021, 4:41 p.m. UTC | #5
Quoting Eric Curtin (2021-10-28 16:26:53)
> Hi Laurent,
> 
> On Wed, 27 Oct 2021 at 22:13, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> >
> > Hi Eric,
> >
> > Thank you for the patch.
> >
> > On Wed, Oct 27, 2021 at 11:04:41AM +0100, Eric Curtin wrote:
> > > xrand --query isn't always available and does not always display all
> > > conneted connectors.
> >
> > Stupid questions, couldn't connectors also be listed through sysfs ?
> >
> > for conn in /sys/class/drm/card*-* ; do status=$(cat $conn/status) ; if [ $status == connected ] ; then echo $conn ; fi ; done
> >
> > I'm not opposed to adding this feature to the cam application, but I
> > wonder if it really belongs here, especially if we consider that a next
> > step would be to print supported modes.

I think it's helpful to have it in cam. Cam has support to render on a
DRM device, but you have to 'know' what device. This is a nice
convenience helper to those who do not know other ways to interogate
DRM.



> 
> Printing modes is where I was gonna do next. I only learned about
> /sys/class/drm/card now
> as a new guy to DRM, I think it would be useful for those who aren't
> familiar with /sys
> directory structure for drm. Finding documentation for this can be
> hard and a tool is easier to maintain anyway.
> 
> Are you thinking maybe a separate binary called drm-info? (drm-utils
> is a taken name by a
> package that is seems not so useful in the context of the cam
> application), etc? We list all
> the equivalent cam information with the "cam -I -c1", it can be hard
> to gather the equivalent
> display info and if we can get them both at the same place, same
> binary, would be nice!
> 
> >
> > > Signed-off-by: Eric Curtin <ecurtin@redhat.com>
> > > ---
> > >  src/cam/main.cpp | 31 ++++++++++++++++++++++++++-----
> > >  src/cam/main.h   |  3 +++
> > >  2 files changed, 29 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> > > index c7f664b9..319cbf4d 100644
> > > --- a/src/cam/main.cpp
> > > +++ b/src/cam/main.cpp
> > > @@ -15,6 +15,11 @@
> > >  #include <libcamera/property_ids.h>
> > >
> > >  #include "camera_session.h"
> > > +
> > > +#ifdef HAVE_KMS
> > > +#include "drm.h"
> > > +#endif
> > > +
> > >  #include "event_loop.h"
> > >  #include "main.h"
> > >  #include "options.h"
> > > @@ -137,6 +142,7 @@ int CamApp::parseOptions(int argc, char *argv[])
> > >                        "Display viewfinder through DRM/KMS on specified connector",
> > >                        "display", ArgumentOptional, "connector", false,
> > >                        OptCamera);
> > > +     parser.addOption(OptListDisplays, OptionNone, "List all displays", "list-displays");
> > >  #endif
> > >       parser.addOption(OptFile, OptionString,
> > >                        "Write captured frames to disk\n"
> > > @@ -202,7 +208,22 @@ int CamApp::run()
> > >               }
> > >       }
> > >
> > > -     /* 2. Create the camera sessions. */
> > > +#ifdef HAVE_KMS
> > > +     /* 2. List all displays. */
> > > +     if (options_.isSet(OptListDisplays)) {
> > > +             std::cout << "Available displays:" << std::endl;
> > > +
> > > +             DRM::Device dev;
> > > +             dev.init();
> >
> > As Umang mentioned, errors should be checked.
> >
> > > +             for (const DRM::Connector &conn : dev.connectors()) {
> > > +                     if (conn.status() == DRM::Connector::Connected) {
> > > +                             std::cout << conn.name() << std::endl;
> > > +                     }
> >
> > No need for curly braces in the inner if.

I would be tempted to put any DRM specific code into src/cam/drm.cpp
though, and try to reduce the code that is added to main.cpp.


> >
> > > +             }
> > > +     }
> > > +#endif
> > > +
> > > +     /* 3. Create the camera sessions. */
> > >       std::vector<std::unique_ptr<CameraSession>> sessions;
> > >
> > >       if (options_.isSet(OptCamera)) {
> > > @@ -229,7 +250,7 @@ int CamApp::run()
> > >               }
> > >       }
> > >
> > > -     /* 3. Print camera information. */
> > > +     /* 4. Print camera information. */
> > >       if (options_.isSet(OptListControls) ||
> > >           options_.isSet(OptListProperties) ||
> > >           options_.isSet(OptInfo)) {
> > > @@ -243,7 +264,7 @@ int CamApp::run()
> > >               }
> > >       }
> > >
> > > -     /* 4. Start capture. */
> > > +     /* 5. Start capture. */
> > >       for (const auto &session : sessions) {
> > >               if (!session->options().isSet(OptCapture))
> > >                       continue;
> > > @@ -257,7 +278,7 @@ int CamApp::run()
> > >               loopUsers_++;
> > >       }
> > >
> > > -     /* 5. Enable hotplug monitoring. */
> > > +     /* 6. Enable hotplug monitoring. */
> > >       if (options_.isSet(OptMonitor)) {
> > >               std::cout << "Monitoring new hotplug and unplug events" << std::endl;
> > >               std::cout << "Press Ctrl-C to interrupt" << std::endl;
> > > @@ -271,7 +292,7 @@ int CamApp::run()
> > >       if (loopUsers_)
> > >               loop_.exec();
> > >
> > > -     /* 6. Stop capture. */
> > > +     /* 7. Stop capture. */
> > >       for (const auto &session : sessions) {
> > >               if (!session->options().isSet(OptCapture))
> > >                       continue;
> > > diff --git a/src/cam/main.h b/src/cam/main.h
> > > index 1c2fab76..72050d27 100644
> > > --- a/src/cam/main.h
> > > +++ b/src/cam/main.h
> > > @@ -21,6 +21,9 @@ enum {
> > >       OptListControls = 256,
> > >       OptStrictFormats = 257,
> > >       OptMetadata = 258,
> > > +#ifdef HAVE_KMS
> > > +     OptListDisplays = 259
> > > +#endif
> > >  };
> > >
> > >  #endif /* __CAM_MAIN_H__ */
> >
> > --
> > Regards,
> >
> > Laurent Pinchart
> >
> 
> Is mise le meas/Regards,
> 
> Eric Curtin
>
Laurent Pinchart Oct. 28, 2021, 6:07 p.m. UTC | #6
On Thu, Oct 28, 2021 at 05:41:31PM +0100, Kieran Bingham wrote:
> Quoting Eric Curtin (2021-10-28 16:26:53)
> > On Wed, 27 Oct 2021 at 22:13, Laurent Pinchart wrote:
> > > On Wed, Oct 27, 2021 at 11:04:41AM +0100, Eric Curtin wrote:
> > > > xrand --query isn't always available and does not always display all
> > > > conneted connectors.
> > >
> > > Stupid questions, couldn't connectors also be listed through sysfs ?
> > >
> > > for conn in /sys/class/drm/card*-* ; do status=$(cat $conn/status) ; if [ $status == connected ] ; then echo $conn ; fi ; done
> > >
> > > I'm not opposed to adding this feature to the cam application, but I
> > > wonder if it really belongs here, especially if we consider that a next
> > > step would be to print supported modes.
> 
> I think it's helpful to have it in cam. Cam has support to render on a
> DRM device, but you have to 'know' what device. This is a nice
> convenience helper to those who do not know other ways to interogate
> DRM.

I'll side with the majority then :-)

> > Printing modes is where I was gonna do next. I only learned about /sys/class/drm/card now
> > as a new guy to DRM, I think it would be useful for those who aren't familiar with /sys
> > directory structure for drm. Finding documentation for this can be
> > hard and a tool is easier to maintain anyway.
> > 
> > Are you thinking maybe a separate binary called drm-info? (drm-utils is a taken name by a
> > package that is seems not so useful in the context of the cam application), etc? We list all
> > the equivalent cam information with the "cam -I -c1", it can be hard to gather the equivalent
> > display info and if we can get them both at the same place, same binary, would be nice!

cam is a tool that is meant to exercise the whole libcamera API, in a
bit of a swiss army knife kind of way. It has a few extra features not
related to cameras as such, including support for DRM/KMS output. I'd
like to keep the focus on the camera side, and not solve every other
side issue that the world may be experiencing. In this specific case,
there's a (in my opinion) not too difficult way to find the connectors
and their states from sysfs, but at the same time the implementation of
a similar feature in cam is not too intrusive (at least so far). I'm
thus OK with it, but if we later add an option to print modes, and then
later something else, I may regret this decision :-)

> > > > Signed-off-by: Eric Curtin <ecurtin@redhat.com>
> > > > ---
> > > >  src/cam/main.cpp | 31 ++++++++++++++++++++++++++-----
> > > >  src/cam/main.h   |  3 +++
> > > >  2 files changed, 29 insertions(+), 5 deletions(-)
> > > >
> > > > diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> > > > index c7f664b9..319cbf4d 100644
> > > > --- a/src/cam/main.cpp
> > > > +++ b/src/cam/main.cpp
> > > > @@ -15,6 +15,11 @@
> > > >  #include <libcamera/property_ids.h>
> > > >
> > > >  #include "camera_session.h"
> > > > +
> > > > +#ifdef HAVE_KMS
> > > > +#include "drm.h"
> > > > +#endif
> > > > +
> > > >  #include "event_loop.h"
> > > >  #include "main.h"
> > > >  #include "options.h"
> > > > @@ -137,6 +142,7 @@ int CamApp::parseOptions(int argc, char *argv[])
> > > >                        "Display viewfinder through DRM/KMS on specified connector",
> > > >                        "display", ArgumentOptional, "connector", false,
> > > >                        OptCamera);
> > > > +     parser.addOption(OptListDisplays, OptionNone, "List all displays", "list-displays");
> > > >  #endif
> > > >       parser.addOption(OptFile, OptionString,
> > > >                        "Write captured frames to disk\n"
> > > > @@ -202,7 +208,22 @@ int CamApp::run()
> > > >               }
> > > >       }
> > > >
> > > > -     /* 2. Create the camera sessions. */
> > > > +#ifdef HAVE_KMS
> > > > +     /* 2. List all displays. */
> > > > +     if (options_.isSet(OptListDisplays)) {
> > > > +             std::cout << "Available displays:" << std::endl;
> > > > +
> > > > +             DRM::Device dev;
> > > > +             dev.init();
> > >
> > > As Umang mentioned, errors should be checked.
> > >
> > > > +             for (const DRM::Connector &conn : dev.connectors()) {
> > > > +                     if (conn.status() == DRM::Connector::Connected) {
> > > > +                             std::cout << conn.name() << std::endl;
> > > > +                     }
> > >
> > > No need for curly braces in the inner if.
> 
> I would be tempted to put any DRM specific code into src/cam/drm.cpp
> though, and try to reduce the code that is added to main.cpp.
> 
> > > > +             }
> > > > +     }
> > > > +#endif
> > > > +
> > > > +     /* 3. Create the camera sessions. */
> > > >       std::vector<std::unique_ptr<CameraSession>> sessions;
> > > >
> > > >       if (options_.isSet(OptCamera)) {
> > > > @@ -229,7 +250,7 @@ int CamApp::run()
> > > >               }
> > > >       }
> > > >
> > > > -     /* 3. Print camera information. */
> > > > +     /* 4. Print camera information. */
> > > >       if (options_.isSet(OptListControls) ||
> > > >           options_.isSet(OptListProperties) ||
> > > >           options_.isSet(OptInfo)) {
> > > > @@ -243,7 +264,7 @@ int CamApp::run()
> > > >               }
> > > >       }
> > > >
> > > > -     /* 4. Start capture. */
> > > > +     /* 5. Start capture. */
> > > >       for (const auto &session : sessions) {
> > > >               if (!session->options().isSet(OptCapture))
> > > >                       continue;
> > > > @@ -257,7 +278,7 @@ int CamApp::run()
> > > >               loopUsers_++;
> > > >       }
> > > >
> > > > -     /* 5. Enable hotplug monitoring. */
> > > > +     /* 6. Enable hotplug monitoring. */
> > > >       if (options_.isSet(OptMonitor)) {
> > > >               std::cout << "Monitoring new hotplug and unplug events" << std::endl;
> > > >               std::cout << "Press Ctrl-C to interrupt" << std::endl;
> > > > @@ -271,7 +292,7 @@ int CamApp::run()
> > > >       if (loopUsers_)
> > > >               loop_.exec();
> > > >
> > > > -     /* 6. Stop capture. */
> > > > +     /* 7. Stop capture. */
> > > >       for (const auto &session : sessions) {
> > > >               if (!session->options().isSet(OptCapture))
> > > >                       continue;
> > > > diff --git a/src/cam/main.h b/src/cam/main.h
> > > > index 1c2fab76..72050d27 100644
> > > > --- a/src/cam/main.h
> > > > +++ b/src/cam/main.h
> > > > @@ -21,6 +21,9 @@ enum {
> > > >       OptListControls = 256,
> > > >       OptStrictFormats = 257,
> > > >       OptMetadata = 258,
> > > > +#ifdef HAVE_KMS
> > > > +     OptListDisplays = 259
> > > > +#endif
> > > >  };
> > > >
> > > >  #endif /* __CAM_MAIN_H__ */

Patch
diff mbox series

diff --git a/src/cam/main.cpp b/src/cam/main.cpp
index c7f664b9..319cbf4d 100644
--- a/src/cam/main.cpp
+++ b/src/cam/main.cpp
@@ -15,6 +15,11 @@ 
 #include <libcamera/property_ids.h>
 
 #include "camera_session.h"
+
+#ifdef HAVE_KMS
+#include "drm.h"
+#endif
+
 #include "event_loop.h"
 #include "main.h"
 #include "options.h"
@@ -137,6 +142,7 @@  int CamApp::parseOptions(int argc, char *argv[])
 			 "Display viewfinder through DRM/KMS on specified connector",
 			 "display", ArgumentOptional, "connector", false,
 			 OptCamera);
+	parser.addOption(OptListDisplays, OptionNone, "List all displays", "list-displays");
 #endif
 	parser.addOption(OptFile, OptionString,
 			 "Write captured frames to disk\n"
@@ -202,7 +208,22 @@  int CamApp::run()
 		}
 	}
 
-	/* 2. Create the camera sessions. */
+#ifdef HAVE_KMS
+	/* 2. List all displays. */
+	if (options_.isSet(OptListDisplays)) {
+		std::cout << "Available displays:" << std::endl;
+
+		DRM::Device dev;
+		dev.init();
+		for (const DRM::Connector &conn : dev.connectors()) {
+			if (conn.status() == DRM::Connector::Connected) {
+				std::cout << conn.name() << std::endl;
+			}
+		}
+	}
+#endif
+
+	/* 3. Create the camera sessions. */
 	std::vector<std::unique_ptr<CameraSession>> sessions;
 
 	if (options_.isSet(OptCamera)) {
@@ -229,7 +250,7 @@  int CamApp::run()
 		}
 	}
 
-	/* 3. Print camera information. */
+	/* 4. Print camera information. */
 	if (options_.isSet(OptListControls) ||
 	    options_.isSet(OptListProperties) ||
 	    options_.isSet(OptInfo)) {
@@ -243,7 +264,7 @@  int CamApp::run()
 		}
 	}
 
-	/* 4. Start capture. */
+	/* 5. Start capture. */
 	for (const auto &session : sessions) {
 		if (!session->options().isSet(OptCapture))
 			continue;
@@ -257,7 +278,7 @@  int CamApp::run()
 		loopUsers_++;
 	}
 
-	/* 5. Enable hotplug monitoring. */
+	/* 6. Enable hotplug monitoring. */
 	if (options_.isSet(OptMonitor)) {
 		std::cout << "Monitoring new hotplug and unplug events" << std::endl;
 		std::cout << "Press Ctrl-C to interrupt" << std::endl;
@@ -271,7 +292,7 @@  int CamApp::run()
 	if (loopUsers_)
 		loop_.exec();
 
-	/* 6. Stop capture. */
+	/* 7. Stop capture. */
 	for (const auto &session : sessions) {
 		if (!session->options().isSet(OptCapture))
 			continue;
diff --git a/src/cam/main.h b/src/cam/main.h
index 1c2fab76..72050d27 100644
--- a/src/cam/main.h
+++ b/src/cam/main.h
@@ -21,6 +21,9 @@  enum {
 	OptListControls = 256,
 	OptStrictFormats = 257,
 	OptMetadata = 258,
+#ifdef HAVE_KMS
+	OptListDisplays = 259
+#endif
 };
 
 #endif /* __CAM_MAIN_H__ */