Controlling exposure and white balance with gstreamer and v4l2src

I am using a Jetson AGX Orin with an Arducam B0459C (a USB 3.0 camera with a 12MP IMX477P sensor). For my application, I need to be able to control exposure, white balance temperature, contrast, saturation, brightness, and gain. I am currently using a python script with OpenCV to successfully control all of these parameters on a Linux virtual machine inside my Windows laptop. For example,

cap = cv2.VideoCapture(0, cv2.CAP_ANY)
# Turn off auto exposure:
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1)
# Set exposure time:
cap.set(cv2.CAP_PROP_EXPOSURE, 50)
# Turn off auto-white temperature balance:
cap.set(cv2.CAP_PROP_AUTO_WB, 0)
#Set white temperature balance value:
cap.set(cv2.CAP_PROP_WB_TEMPERATURE, 2498)
# Set brightness:
cap.set(cv2.CAP_PROP_BRIGHTNESS, 10)
# Set gain:
cap.set(cv2.CAP_PROP_GAIN, 200)
# etc...

Next, I am attempting to use the camera with gstreamer on the Jetson AGX Orin and then use OpenCV to analyze the image. I assume that I must use v4l2src.

For v4l2src, I see that brightness, contrast, and saturation can be controlled in gstreamer by following the instructions here. How do I control exposure, white temperature balance, and gain?

Hi, you use the extra-controls for that. For example:


Depending on which JetPack version you’re using, you may need to extend v4l2src to include support for V4L2_CTRL_TYPE_INTEGER64, which is the control type used by the Tegra camera.

Thank you! I will give that a try.

I see the documentation states that the control name is always lowercase with ‘_’ for any non-alphanumeric character. I assume that the control name is taken from the latter portion of the cv2.CAP_PROP_XXX parameter? For example, you knew that “exposure” corresponds to “cv2.CAP_PROP_EXPOSURE?”

If so, I will attempt the following:


I think I might be able to answer my own question…

This webpage states that I can get the list of control names via $ v4l2-ctl --list-ctrls. I should have suspected that the v4l2-ctl parameter names would be used.

So instead, I will attempt the following:


Am I going in the right direction now?

Sure, those options look good. Just keep in mind that the control type might not be supported in v4l2src. Also, you can set multiple controls at once:


In case you need it, here’s the patch I applied to gst-plugins-good to enable Tegra camera control support on GStreamer 1.14.5:

Author: Miguel Taylor <>
Date:   Thu Apr 28 18:09:44 2022 -0600

    Add support for tegra camera ctrls to v4l2src

diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c
index d3dbd42..e91cbee 100644
--- a/sys/v4l2/v4l2_calls.c
+++ b/sys/v4l2/v4l2_calls.c
@@ -326,6 +326,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
     switch (control.type) {
       case V4L2_CTRL_TYPE_INTEGER:
+      case V4L2_CTRL_TYPE_INTEGER64:
       case V4L2_CTRL_TYPE_BOOLEAN:
       case V4L2_CTRL_TYPE_MENU:
@@ -382,9 +383,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
         v4l2object->has_alpha_component = TRUE;
-        GST_DEBUG_OBJECT (e,
-            "ControlID %s (%x) unhandled, FIXME",, n);
+        /* Tegra camera control IDs */
     if (n !=
@@ -430,6 +429,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
     switch (control.type) {
       case V4L2_CTRL_TYPE_INTEGER:
+      case V4L2_CTRL_TYPE_INTEGER64:
         channel->min_value = control.minimum;
         channel->max_value = control.maximum;
@@ -945,17 +945,19 @@ gboolean
 gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
     int attribute_num, const int value)
-  struct v4l2_control control = { 0, };
-  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "setting value of attribute %d to %d",
-      attribute_num, value);
+  struct v4l2_ext_control control_array[1];
+  struct v4l2_ext_controls ctrls;
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;
- = attribute_num;
-  control.value = value;
-  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
+  control_array[0].id = attribute_num;
+  control_array[0].value = value;
+  control_array[0].value64 = value;
+  ctrls.which = V4L2_CTRL_CLASS_CAMERA;
+  ctrls.count = 1;
+  ctrls.controls = control_array;
+  if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
     goto ctrl_failed;
   return TRUE;

Thank you! This has been extremely helpful. I’ll get started.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.