GrabChunks#

#include <stdio.h>
#include <stdlib.h>
#include "ItalaApiC/ItalaC.h"

#define ACQUIRE_COUNT 10

ItalaError ErrorManager(ItalaError e) {
  size_t sizeMessage = 255;
  char* message = (char*)malloc(sizeof(char) * sizeMessage);
  ERR_GetLastErrorMessage(message, &sizeMessage);
  printf("\nITALA ERROR (%d):\t%s, %zu char", ERR_GetLastErrorCode(), message, sizeMessage);
  free(message);
  return e;
}

int main(int argc, char** argv) {
  printf("***** Grab chunks example started. *****\n");
  ItalaError error = ItalaErrorSuccess;

  error = SYS_Initialize();
  if (error) return ErrorManager(error);

  size_t devicesInfoSize = 0;
  error = SYS_EnumerateDevices(700);
  if (error) return ErrorManager(error);
  error = SYS_GetDeviceCount(&devicesInfoSize);
  if (error) return ErrorManager(error);
  if (devicesInfoSize == 0) {
    printf("No devices found. Example canceled.\n");
    return ItalaErrorError;
  }
  DeviceInfo deviceInfo;
  error = SYS_GetDeviceByIndex(0, &deviceInfo);
  if (error) return ErrorManager(error);
  if (deviceInfo.AccessStatus != AvailableReadWrite) {
    printf("Target device is unaccessible in RW mode. Example canceled.\n");
    return ItalaErrorError;
  }

  H_DEVICE hDevice = NULL;
  error = SYS_CreateDevice(deviceInfo, &hDevice);
  if (error) return ErrorManager(error);
  printf("First device found is initialized.\n");
  printf("Enabling chunk data..\n");

  H_NODEMAP hNodeMap = NULL;
  error = DEV_GetNodeMap(hDevice, &hNodeMap);
  if (error) return ErrorManager(error);

  // Enable the auto exposure time functionality to cause changes in the exposure
  // time value when the scene changes or the camera itself is moved.
  H_NODE hNodeExposureAuto = NULL;
  error = NODEMAP_GetNode(hNodeMap, "ExposureAuto", &hNodeExposureAuto);
  if (error) return ErrorManager(error);
  bool isWritable = false;
  error = IsNodeWritable(hNodeExposureAuto, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to activate auto exposure time mode. Aborting.\n");
    return ItalaErrorError;
  }
  int64_t originalExposureAuto = 0;
  error = NODE_EnumerationGetIntValue(hNodeExposureAuto, &originalExposureAuto);
  if (error) return ErrorManager(error);
  error = NODE_FromString(hNodeExposureAuto, "Continuous");
  if (error) return ErrorManager(error);

  // The chunk data functionality is enabled via the "ChunkModeActive" feature.
  H_NODE hNodeChunkModeActive = NULL;
  error = NODEMAP_GetNode(hNodeMap, "ChunkModeActive", &hNodeChunkModeActive);
  if (error) return ErrorManager(error);
  isWritable = false;
  error = IsNodeWritable(hNodeChunkModeActive, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to activate chunk mode. Aborting.\n");
    return ItalaErrorError;
  }
  bool originalChunkModeActive = false;
  error = NODE_BooleanGetValue(hNodeChunkModeActive, &originalChunkModeActive);
  if (error) return ErrorManager(error);
  error = NODE_BooleanSetValue(hNodeChunkModeActive, true);
  if (error) return ErrorManager(error);

  // Each chunk data available can be enabled individually. In this case, exposure
  // time, pixel format and frame timestamp chunks are activated.
  // First select the exposure time chunk via the selector and enable it via the
  // "ChunkEnable" feature.
  H_NODE hNodeChunkSelector = NULL;
  error = NODEMAP_GetNode(hNodeMap, "ChunkSelector", &hNodeChunkSelector);
  if (error) return ErrorManager(error);
  isWritable = false;
  error = IsNodeWritable(hNodeChunkSelector, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to retrieve chunk selector. Aborting.\n");
    return ItalaErrorError;
  }
  error = NODE_FromString(hNodeChunkSelector, "ExposureTime");
  if (error) return ErrorManager(error);

  H_NODE hNodeChunkEnable = NULL;
  error = NODEMAP_GetNode(hNodeMap, "ChunkEnable", &hNodeChunkEnable);
  if (error) return ErrorManager(error);
  isWritable = false;
  bool originalExposureTimeChunkEnabled = false;
  error = NODE_BooleanGetValue(hNodeChunkEnable, &originalExposureTimeChunkEnabled);
  if (error) return ErrorManager(error);
  error = NODE_BooleanSetValue(hNodeChunkEnable, true);
  if (error) return ErrorManager(error);

  // Do the same for frame ID chunk.
  error = NODE_FromString(hNodeChunkSelector, "FrameID");
  if (error) return ErrorManager(error);
  bool originalFrameIDChunkEnabled = false;
  error = NODE_BooleanGetValue(hNodeChunkEnable, &originalFrameIDChunkEnabled);
  if (error) return ErrorManager(error);

  error = NODE_FromString(hNodeChunkSelector, "Timestamp");
  if (error) return ErrorManager(error);
  bool originalTimestampChunkEnabled = false;
  error = NODE_BooleanGetValue(hNodeChunkEnable, &originalTimestampChunkEnabled);
  if (error) return ErrorManager(error);

  printf("\n");

  error = DEV_StartAcquisition(hDevice);
  if (error) return ErrorManager(error);

  printf("Acquisition started with chunk functionality enabled.\n\n");

  H_IMAGE images[ACQUIRE_COUNT];
  H_IMAGE hImage = NULL;
  bool isIncomplete = false;
  for (size_t i = 0; i < ACQUIRE_COUNT; i++) {
    error = DEV_GetNextImage(hDevice, 1000, &hImage);
    if (error) return ErrorManager(error);
    error = IMG_IsIncomplete(hImage, &isIncomplete);
    if (isIncomplete) {
      // Report some info if the image is partially filled.
      printf("Incomplete image.\n");
      size_t filled = 0;
      size_t payloadSize = 0;
      error = IMG_GetBytesFilled(hImage, &filled);
      if (error) return ErrorManager(error);
      error = IMG_GetPayloadSize(hImage, &payloadSize);
      if (error) return ErrorManager(error);
      printf("\tBytes filled: %zu/%zu", filled, payloadSize);
    } else {
      printf("Image %zu grabbed.\n", i);
    }

    // Add the image to the acquired frames list so that image chunks can be
    // retrieved and displayed after che grab.
    images[i] = hImage;

    // The image IS NOT disposed here since it's needed afterwards to get and
    // display the attached chunk data.
    hImage = NULL;
  }

  printf("\n");

  // The chunks embedded in the available images are ready to be read.
  H_NODE hNodeExposureTime = NULL;
  H_NODE hNodeFrameID = NULL;
  H_NODE hNodeTimestamp = NULL;
  double exposureTime = 0;
  int64_t frameId = 0;
  int64_t timestamp = 0;
  for (size_t i = 0; i < ACQUIRE_COUNT; i++) {
    hImage = images[i];
    printf("Retrieving chunks for image %zu ..", i);

    // Check if the acquired image has embedded chunk data.
    bool hasChunckData = false;
    error = IMG_HasChunkData(hImage, &hasChunckData);
    if (error) return ErrorManager(error);
    if (hasChunckData) {
      // Chunk data is exposed as a set GenICam features which names ar
      // regulated by the SFNC specification. In general, the names of
      // chunk features are defined by prepending the "Chunk" prefix
      // (e.g. ChunkExposureTime) to the equivalent standard feature
      // (e.g. ExposureTime).
      error = IMG_GetChunkNode(hImage, "ChunkExposureTime", &hNodeExposureTime);
      if (error) return ErrorManager(error);
      error = IMG_GetChunkNode(hImage, "ChunkFrameID", &hNodeFrameID);
      if (error) return ErrorManager(error);
      error = IMG_GetChunkNode(hImage, "ChunkTimestamp", &hNodeTimestamp);
      if (error) return ErrorManager(error);

      error = NODE_FloatGetValue(hNodeExposureTime, &exposureTime);
      if (error) return ErrorManager(error);
      error = NODE_IntegerGetValue(hNodeFrameID, &frameId);
      if (error) return ErrorManager(error);
      error = NODE_IntegerGetValue(hNodeTimestamp, &timestamp);
      if (error) return ErrorManager(error);

      printf("\tChunkExposureTime: %f\n", exposureTime);
      printf("\tChunkFrameID: %jd\n", frameId);
      printf("\tChunkTimestamp: %jd\n", timestamp);
    } else {
      printf("\tNo chunk data attached.\n");
    }
    // The image can now be disposed: it's not required anymore.
    error = IMG_Dispose(hImage);
    hImage = NULL;
    if (error) return ErrorManager(error);
    printf("\n");
  }

  // The acquisition must be stopped AFTER the acquired images have been used
  // (to display chunk data, in this case). If the acquisition was stopped
  // prematurely, errors may have occurred when accessing the image data (released
  // by the library).
  error = DEV_StopAcquisition(hDevice);
  if (error) return ErrorManager(error);

  error = NODE_EnumerationSetIntValue(hNodeExposureAuto, originalExposureAuto);
  if (error) return ErrorManager(error);

  error = NODE_FromString(hNodeChunkSelector, "ExposureTime");
  if (error) return ErrorManager(error);
  error = NODE_BooleanSetValue(hNodeChunkEnable, originalExposureTimeChunkEnabled);
  if (error) return ErrorManager(error);

  error = NODE_FromString(hNodeChunkSelector, "FrameID");
  if (error) return ErrorManager(error);
  error = NODE_BooleanSetValue(hNodeChunkEnable, originalFrameIDChunkEnabled);
  if (error) return ErrorManager(error);

  error = NODE_FromString(hNodeChunkSelector, "Timestamp");
  if (error) return ErrorManager(error);
  error = NODE_BooleanSetValue(hNodeChunkEnable, originalTimestampChunkEnabled);
  if (error) return ErrorManager(error);

  error = DEV_Dispose(hDevice);
  hDevice = NULL;
  if (error) return ErrorManager(error);
  printf("Device instance disposed.\n");

  error = SYS_Dispose();
  if (error) return ErrorManager(error);
  printf("System instance disposed.\n");
  return 0;
}