Old image broken after setting new camport

I’m building a multi camera application and and I have problems accessing more than one camera at once.
I load the cameras roughly with these two functions:

IMG img0, img1;
LoadImageFile("GenICam.vin", img0);
CS2SetCamport(img0, 1, 0, img1);

Now I would expect that I can access the cameras as configured with the GenICam Browser.

  • Camera 0 with “img0”
  • Camera 1 with “img1”

However, only camera 1 works as excepted. Calling G2Grab fails on camera 0. If I do not call CS2SetCamport camera 0 works fine, so I’m quite sure this is not a hardware issue.

I also read in the documentation for GS2SetCamPort:

“The old image still exists but all driver interfaces ‘move’ to the new image”

Sounds like that has something to do with it, but how can I prevent the old image from breaking, so that I can access both cameras at once.

You are right. Unfortunately the documentation only give’s a hint on what happen after calling CS2SetCamport.
After that call you cannot access the “old image” as camera any more, because the required interface is gone (moved).
However, the handle stays valid and provides access to the current image buffer. Think of it like a image file loaded from disc. As a consequence you must release the “old image” otherwise you would leak memory.

CS2SetCamport(img0, 1, 0, img1);
ReleaseObj(img0);

I omitted error handling for simplicity.

In order to get access to camera 0 you have to call

LoadImageFile("GenICam.vin", img0);

again.
Please note, that for VIN drivers LoadImageFile will always access port 0 (and board 0 if available).
Therefore, a good procedure for accessing multiple cameras is to load port 0 last. E.g.

IMG img0 = nullptr;
IMG img1 = nullptr;
IMG img2 = nullptr;

LoadImageFile("GenICam.vin", img0); // port 0 is occupied, load again would fail
CS2SetCamport(img0, 2, 0, img2); // port 0 is free again, load will work
RelaseObj(img0);
 
LoadImageFile("GenICam.vin", img0); // port 0 is occupied, load again would fail
CS2SetCamport(img0, 1, 0, img1); // port 0 is free again, load will work
RelaseObj(img0);

LoadImageFile("GenICam.vin", img0); // port 0 is occupied, load again would fail
2 Likes

Thanks, works.
I also tested an option in the GenIcam.ini

AutoSwitchEnable=1

Now it even works without calling CS2SetCamport.
I’m not sure what it does exactly?

AutoSwitchEnable=1

Can indeed be convenient in some situations. It tells the driver to automatically switch to the next free camera if port 0 is occupied. Therefore load won’t fail and no CS2SetCamport is required.

However I would discourage you from using it because of the following reasons:

  • It only works for GigE Vision devices e.g not for USB3 Vision devices.
  • There is no way to know in advance which camera you will actually get.

You can also use the following helper function which does exactly what you want all the time:

/// Opens port with the given \a portNumber on the given \a driver.
/// \return \b nullptr on error; \b IMG handle of opened driver port.
IMG OpenDriverPort(const char *driver, int portNumber)
{
  IMG hImg = nullptr;
  
  if(LoadImageFile(driver, hImg))
  {
    cvbdim_t currentPort = -1;
    if(CS2GetCamPort(hImg, currentPort) >= 0 && currentPort != portNumber)
    {
      IMG hNewPort = nullptr;
      if(CS2SetCamPort(hImg, portNumber, 0, hNewPort) >= 0)
      {
        ReleaseObject(hImg);
        hImg = hNewPort;
      }
    }
  }

  return hImg;
}

You can call it like this:

IMG hFirstCamera = OpenDriverPort("GenICam.vin", 0);
IMG hSecondCamera = OpenDriverPort("GenICam.vin", 1);
1 Like

And if you are starting a new CVB application you can also use automatic life-time management of CVB reference counted objects. See CvbHandle.hpp and the comments on how to do that.

For me this simplifies development a lot. :relaxed:

1 Like