[libcamera-devel] [PATCH v3 3/9] libcamera: media_device: Handle ancillary links in populateLinks()
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Fri Dec 10 01:59:37 CET 2021
Hi Dan,
On Wed, Dec 08, 2021 at 10:10:08PM +0000, Daniel Scally wrote:
> On 08/12/2021 08:26, Laurent Pinchart wrote:
> > On Tue, Dec 07, 2021 at 10:45:06PM +0000, Daniel Scally wrote:
> >> The populateLinks() function can't currently handle ancillary links
> >> which causes an error to be thrown in process() when the MediaObject
> >> cannot be cast to a MediaPad.
> >>
> >> Add explicit handling for the different link types, creating either
> >> pad-2-pad links or else storing the pointer to the ancillary device
> >> MediaEntity in the ancillaryEntities_ member of the primary.
> >>
> >> Signed-off-by: Daniel Scally <djrscally at gmail.com>
> >> ---
> >> Changes in v3:
> >>
> >> - Split out the new macro
> >> - Fixed some style errors and comments
> >> - Added a default case
> >>
> >> src/libcamera/media_device.cpp | 55 ++++++++++++++++++++++++----------
> >> 1 file changed, 39 insertions(+), 16 deletions(-)
> >
> > I'm afraid this patch now conflicts, could you please rebase it ?
> >
> >> diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
> >> index 4df0a27f..fb332445 100644
> >> --- a/src/libcamera/media_device.cpp
> >> +++ b/src/libcamera/media_device.cpp
> >> @@ -693,45 +693,68 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
> >> {
> >> struct media_v2_link *mediaLinks = reinterpret_cast<struct media_v2_link *>
> >> (topology.ptr_links);
> >> + MediaEntity *ancillary;
> >> + MediaEntity *primary;
> >> + MediaLink *link;
> >>
> >> for (unsigned int i = 0; i < topology.num_links; ++i) {
> >> /*
> >> - * Skip links between entities and interfaces: we only care
> >> - * about pad-2-pad links here.
> >> + * Skip links between entities and interfaces: interfaces are
> >> + * not created as MediaObjects at this time, so the source and
> >> + * sink pointers would never be found.
> >> */
> >> if ((mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) ==
> >> MEDIA_LNK_FL_INTERFACE_LINK)
> >> continue;
> >>
> >> - /* Store references to source and sink pads in the link. */
> >> + /* Look up the source and sink objects. */
> >> unsigned int source_id = mediaLinks[i].source_id;
> >> - MediaPad *source = dynamic_cast<MediaPad *>
> >> - (object(source_id));
> >> + MediaObject *source = object(source_id);
> >> if (!source) {
> >> LOG(MediaDevice, Error)
> >> - << "Failed to find pad with id: "
> >> + << "Failed to find MediaObject with id: "
> >> << source_id;
> >> return false;
> >> }
> >>
> >> unsigned int sink_id = mediaLinks[i].sink_id;
> >> - MediaPad *sink = dynamic_cast<MediaPad *>
> >> - (object(sink_id));
> >> + MediaObject *sink = object(sink_id);
> >> if (!sink) {
> >> LOG(MediaDevice, Error)
> >> - << "Failed to find pad with id: "
> >> + << "Failed to find MediaObject with id: "
> >> << sink_id;
> >> return false;
> >> }
> >>
> >> - MediaLink *link = new MediaLink(&mediaLinks[i], source, sink);
> >> - if (!addObject(link)) {
> >> - delete link;
> >> - return false;
> >> - }
> >> + switch (mediaLinks[i].flags & MEDIA_LNK_FL_LINK_TYPE) {
> >> + case MEDIA_LNK_FL_DATA_LINK:
> >> + link = new MediaLink(&mediaLinks[i],
> >> + dynamic_cast<MediaPad *>(source),
> >> + dynamic_cast<MediaPad *>(sink));
> >
> > We'll crash if the source or sink isn't a pad (dynamic_cast will return
> > nullptr in that case). This shouldn't happen unless the kernel reports
> > an incorrect topology, but it would still be nice to protect against
> > that. How about the following (untested) ?
> >
> > case MEDIA_LNK_FL_DATA_LINK: {
> > MediaPad *sourcePad = dynamic_cast<MediaPad *>(source);
> > if (!sourcePad) {
> > LOG(MediaDevice, Error)
> > << "Source MediaObject " << source_id
> > << " is not a pad";
> > return false;
> > }
> >
> > MediaPad *sinkPad = dynamic_cast<MediaPad *>(sink);
> > if (!sinkPad) {
> > LOG(MediaDevice, Error)
> > << "Sink MediaObject " << sink_id
> > << " is not a pad";
> > return false;
> > }
> >
> > MediaLink *link = new MediaLink(&mediaLinks[i],
> > sourcePad, sinkPad);
> > if (!addObject(link)) {
> > delete link;
> > return false;
> > }
> >
> > link->source()->addLink(link);
> > link->sink()->addLink(link);
> >
> > break;
> > }
> >
> > case MEDIA_LNK_FL_ANCILLARY_LINK: {
> > MediaEntity *primary = dynamic_cast<MediaEntity *>(source);
> > if (!primary) {
> > LOG(MediaDevice, Error)
> > << "Source MediaObject " << source_id
> > << " is not an entity";
> > return false;
> > }
> >
> > MediaEntity *ancillary = dynamic_cast<MediaEntity *>(sink);
> > if (!ancillary) {
> > LOG(MediaDevice, Error)
> > << "Sink MediaObject " << sink_id
> > << " is not an entity";
> > return false;
> > }
> >
> > primary->addAncillaryEntity(ancillary);
> > break;
> > }
> >
> > Or is it overkill ?
>
> I lean towards overkill to be honest; since creating data links on the
> kernel side is through media_create_pad_link(), which explicitly sets
> the source and sink to pads. So someone would have to invent a new
> function to add the link in a way that would be broken.
>
> Happy to do it though if you prefer.
I agree that having detailed messages is overkill, but I'd like to at
least avoid crashing in case something goes wrong (during kernel
development for instance). Maybe the following ?
case MEDIA_LNK_FL_DATA_LINK: {
MediaPad *sourcePad = dynamic_cast<MediaPad *>(source);
MediaPad *sinkPad = dynamic_cast<MediaPad *>(sink);
if (!sourcePad || !sinkPad) {
LOG(MediaDevice, Error)
<< "Source or sink is not a pad";
return false;
}
MediaLink *link = new MediaLink(&mediaLinks[i],
sourcePad, sinkPad);
if (!addObject(link)) {
delete link;
return false;
}
link->source()->addLink(link);
link->sink()->addLink(link);
break;
}
case MEDIA_LNK_FL_ANCILLARY_LINK: {
MediaEntity *primary = dynamic_cast<MediaEntity *>(source);
MediaEntity *ancillary = dynamic_cast<MediaEntity *>(sink);
if (!primary || !ancillary) {
LOG(MediaDevice, Error)
<< "Source or sink is not an entity";
return false;
}
primary->addAncillaryEntity(ancillary);
break;
}
> >> + if (!addObject(link)) {
> >> + delete link;
> >> + return false;
> >> + }
> >> +
> >> + link->source()->addLink(link);
> >> + link->sink()->addLink(link);
> >> +
> >> + break;
> >> +
> >> + case MEDIA_LNK_FL_ANCILLARY_LINK:
> >> + primary = dynamic_cast<MediaEntity *>(source);
> >> + ancillary = dynamic_cast<MediaEntity *>(sink);
> >>
> >> - source->addLink(link);
> >> - sink->addLink(link);
> >> + primary->addAncillaryEntity(ancillary);
> >> +
> >> + break;
> >> +
> >> + default:
> >> + LOG(MediaDevice, Warning)
> >> + << "Unknown media link type";
> >> +
> >> + break;
> >> + }
> >> }
> >>
> >> return true;
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list