Creating a fake stream with a specific video pattern produced with opencv

I’m trying to build a fake camera source with my own specific pattern using opencv. However the camera starts but seems to never get picked up by the arvtools/arvviewer.

Here’s my code:

#include <arv.h>
#include <glib.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <signal.h>

// Define image properties
#define WIDTH 320
#define HEIGHT 240
#define PIXEL_FORMAT ARV_PIXEL_FORMAT_MONO8 // Using MONO8 for simplicity

struct FillPatternData {
  guint64 frame_counter;
  int width;
  int height;
};

// Correct callback signature matching ArvFakeCameraFillPattern
void fill_pattern_callback(ArvBuffer *buffer, void *user_data, guint32 width,
                           guint32 height, guint32 padding_x) {
  FillPatternData *data = static_cast<FillPatternData *>(user_data);

  // Generate a new 8-bit grayscale image using OpenCV
  cv::Mat gray_image(data->height, data->width, CV_8UC1, cv::Scalar(0));

  // Create a dynamic pattern that changes with frame_counter
  // For simplicity, we'll create a moving horizontal gradient
  for (int y = 0; y < data->height; y++) {
    for (int x = 0; x < data->width; x++) {
      gray_image.at<uchar>(y, x) =
          static_cast<uchar>((x + data->frame_counter) % 256);
    }
  }

  // Get the buffer data pointer and size
  size_t buffer_size;
  void *buffer_data = (void *)arv_buffer_get_data(buffer, &buffer_size);
  if (!buffer_data) {
    std::cerr << "Failed to get buffer data" << std::endl;
    return;
  }

  // Ensure that the generated image fits into the buffer
  size_t image_size = data->width * data->height; // 1 byte per pixel for MONO8
  if (image_size > buffer_size) {
    std::cerr << "Image size exceeds buffer size. Image size: " << image_size
              << ", Buffer size: " << buffer_size << std::endl;
    return;
  }

  // Copy the grayscale image data into the buffer
  memcpy(buffer_data, gray_image.data, image_size);

  // Increment frame counter
  data->frame_counter++;
}

static gboolean stop = FALSE;

static void control_c_signal(int signal) { stop = TRUE; }

int main(int argc, char **argv) {
  // Initialize the type system (required by GObject in older GLib versions)
#if !GLIB_CHECK_VERSION(2, 35, 0)
  g_type_init();
#endif

  // Initialize Aravis
  arv_update_device_list();

  // Set the GenICam XML file for the fake camera
  arv_set_fake_camera_genicam_filename("fake_camera_genicam.xml");

  // Create a fake GigE Vision camera
  ArvFakeCamera *gv_fake_camera =
      arv_fake_camera_new_full("3", "fake_camera_genicam.xml");
  if (!gv_fake_camera) {
    std::cerr << "Failed to create fake camera" << std::endl;
    return EXIT_FAILURE;
  }

  // Initialize fill pattern data
  FillPatternData fill_data;
  fill_data.frame_counter = 0;
  fill_data.width = WIDTH;
  fill_data.height = HEIGHT;

  // Set fill pattern callback with the correct signature
  arv_fake_camera_set_fill_pattern(ARV_FAKE_CAMERA(gv_fake_camera),
                                   fill_pattern_callback, &fill_data);

  // Set trigger frequency (frame rate)
  arv_fake_camera_set_trigger_frequency(ARV_FAKE_CAMERA(gv_fake_camera),
                                        10.0); // 10 FPS

  std::cout << "Fake Aravis camera is running. Press Ctrl+C to stop."
            << std::endl;

  // Handle SIGINT and SIGTERM to allow graceful exit
  signal(SIGINT, control_c_signal);
  signal(SIGTERM, control_c_signal);

  // Create and run the main loop
  GMainLoop *main_loop = g_main_loop_new(NULL, FALSE);

  // Run the main loop until interrupted
  while (!stop) {
    g_main_context_iteration(NULL, FALSE);
  }

  // Cleanup
  g_main_loop_unref(main_loop);
  g_object_unref(gv_fake_camera);

  return EXIT_SUCCESS;
}

The xml context I used:

<?xml version="1.0" encoding="UTF-8"?>
<GenICamXML>
  <Device>
    <DeviceModelName>Fake_Aravis_Camera</DeviceModelName>
    <DeviceVendorName>FakeVendor</DeviceVendorName>
    <SerialNumber>3</SerialNumber>
    
    <!-- Pixel Format Enumeration -->
    <PixelFormat>
        <EnumEntry name="Mono8">
    <Value>0x01080001</Value> <!-- Standard GenICam value for Mono8 -->
  </EnumEntry>
      <!-- You can add more pixel formats here if needed -->
    </PixelFormat>
    
    <!-- Width Parameter -->
    <Width>
      <Int64Min>1</Int64Min>
      <Int64Max>800</Int64Max>
      <Int64Inc>1</Int64Inc>
      <Int64Default>320</Int64Default>
    </Width>
    
    <!-- Height Parameter -->
    <Height>
      <Int64Min>1</Int64Min>
      <Int64Max>600</Int64Max>
      <Int64Inc>1</Int64Inc>
      <Int64Default>240</Int64Default>
    </Height>
    
    <!-- Trigger Frequency Parameter -->
    <TriggerFrequency>
      <FloatMin>0.0</FloatMin>
      <FloatMax>1000.0</FloatMax>
      <FloatInc>0.1</FloatInc>
      <FloatDefault>10.0</FloatDefault>
    </TriggerFrequency>
    
    <!-- Acquisition Mode Enumeration -->
    <AcquisitionMode>
      <EnumEntry name="Continuous">
        <Value>0</Value>
      </EnumEntry>
      <EnumEntry name="SingleFrame">
        <Value>1</Value>
      </EnumEntry>
      <EnumEntry name="MultiFrame">
        <Value>2</Value>
      </EnumEntry>
    </AcquisitionMode>
    
    <!-- Add more parameters as needed -->
  </Device>
<GenICamXML/>

I can’t get the camera to appear in the viewer or Arvtoos

I’m working on:

  • Aravis version 0.8.33
  • OS: 5.10.192-tegra
  • Hardware arm64

Hi,

How did you build your genicam file ? I doubt it validates using Genicam schema.

Take a look at arv/arv-fake-camera.xml for the original fake camera Genicam data.

Emmanuel.