How to set Sensor Gain and Exposure Time By Argus API under Manual mode

I 'm running Argus yuvJpeg sample,It seem like the app set Sensor Gain auto.
I just want to know how to disable auto gain control by the app and set fixed gain and exposeure time by Argus API.
Are there some example for reference?

Hi,

Check the documentation in the following link: https://docs.nvidia.com/jetson/l4t-multimedia/classArgus_1_1ISourceSettings.html.

First I would check the sensor capabilities for the mode being used, for instance, to check legal exposure and gain ranges:

Range <uint64_t> exposure = iSensorMode->getExposureTimeRange();
Range <float> gain = iSensorMode->getAnalogGainRange();
PRODUCER_PRINT("[%u] Exposure=(%lu,%lu) Gain=(%f,%f)\n", i, exposure.min(), exposure.max(), gain.min(), gain.max());

In my setup, the result is:

PRODUCER: [0] Exposure=(13000,683709000) Gain=(1.000000,16.000000)

Then with this information, you can set the desired ranges, for instance:

iSourceSettings->setExposureTimeRange(Range<uint64_t>{15000, 15000});
iSourceSettings->setGainRange(Range<float>{16,16});

Thank you very much for your information.
It is very clear for my question.

Hi,

I try to check the sensor capabilities on ExposureTime and gain with following code:
Range<uint64_t> exposure = iSourceSettings->getExposureTimeRange();
Range gain = iSourceSettings->getGainRange();
printf(“exposure(%lu,%lu) gain(%f %f)\n”,exposure.min(),exposure.max(),gain.min(),gain.max());

In my setup the result is:

exposure(1000000,10000000) gain(1.000000,64.0000000)

the result is not match the value defined in the driver
#define SC130GS_MIN_GAIN (10)
#define SC130GS_MAX_GAIN (1180)
#define SC130GS_MIN_EXPOSURE_COARSE (10)
#define SC130GS_MAX_EXPOSURE_COARSE (40000000)

when call fuction to set sensor exposure
iSourceSettings->setExposureTimeRange(Range<uint64_t>{5000000,5000000}
the correspongding sensor hal control function(v4l2_ctrl_ops → TEGRA_CAMERA_CID_COARSE_TIME) not been called

Can you please help me to check related way is correctly?

the result is showing in my setup
exposure(1000000,10000000) gain(1.000000,64.0000000)
the above value config on device tree.

Currently, I have disable Auto seting with following code:
status = iAutoControlSettings->setAeAntibandingMode( AE_ANTIBANDING_MODE_OFF);
EXIT_IF_NOT_OK(status, “Failed to setAeAntibandingMode()”);

	status = iAutoControlSettings->setAeLock(true);
	EXIT_IF_NOT_OK(status, "Failed to setAeLock()");

	status = iAutoControlSettings->setAwbLock(true);
	EXIT_IF_NOT_OK(status, "Failed to setAwbLock()");

	status = iAutoControlSettings->setExposureCompensation(0.0f);
	EXIT_IF_NOT_OK(status, "Failed to setExposureCompensation()");

	status = iAutoControlSettings->setIspDigitalGainRange(Range<float>(1.0f,1.0f));
	EXIT_IF_NOT_OK(status, "Failed to setIspDigitalGainRange()");

	ISourceSettings* iSourceSettings = interface_cast<ISourceSettings>(iRequest->getSourceSettings());
	EXIT_IF_NULL(iRequest, "Failed to get ISourceSettings");

But when call :
status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(200000, 200000));
status = iSourceSettings->setGainRange(Range(1.0f, 1.0f));
It have no effect and I still don’t see sensor hal control function(v4l2_ctrl_ops → TEGRA_CAMERA_CID_COARSE_TIME) been called.

Are there something missing for config fixed ExposureTime and Gain?

Hi 27653276,
May i know which L4T version you are using? and if you are using a sensor driver which has 32-bitt controls?
Kindly note that 32-bit controls have been deprecated in the latest L4T versions. The 32-bit controls are replaced with the following 64-bit controls.

  1. TEGRA_CAMERA_CID_COARSE_TIME replaced with TEGRA_CAMERA_CID_EXPOSURE
  2. TEGRA_CAMERA_CID_FRAME_LENGTH replaced with TEGRA_CAMERA_CID_FRAME_RATE

You may see an equivalent ioctl call with TEGRA_CAMERA_CID_EXPOSURE when setting exposure.

Hi Waiss,

I appreciate your reponse!

I’m using L4T R28.2.1 and confirm that sensor driver has 32 bit controls by refer to struct v4l2_ctrl.
in the file (kernel/include/media/v4l2-ctrls.h) have define ‘u32 id’.
I also confirm I can set exposure time and gain by v4l2 ioctl.
I also find that augus_camera application can set sensor exposure time and gain.

I also confirmm there are not any another equivalent ioctl call, because there are the debug message print in the ioctl callbcak.

I just post my test code ,if you interested it.

#include <stdio.h>
#include <Argus/Argus.h>
#include <EGLStream/EGLStream.h>

using namespace Argus;

#define EXIT_IF_NULL(val,msg)   \
        {if (!val) {printf("%s\n",msg); return 1;}}

#define EXIT_IF_NOT_OK(val,msg) \
        {if (val!=STATUS_OK) {printf("%s\n",msg); return 1;}}

int testCapture(ICaptureSession* iSession);

int main(int argc, char**argv) 
{
	std::vector<CameraDevice*> cameraDevices;

	// create a camera provider
	UniqueObj<CameraProvider> cameraProvider(CameraProvider::create());
	ICameraProvider* iCameraProvider = interface_cast<ICameraProvider>(cameraProvider);
	EXIT_IF_NULL(iCameraProvider, "Could not get camera provider");
	printf("Argus Version: %s\n", iCameraProvider->getVersion().c_str());

	// get the status of the provider
	Argus::Status status = iCameraProvider->getCameraDevices(&cameraDevices);
	EXIT_IF_NOT_OK(status, "Failed to get camera devices\r\n");
	EXIT_IF_NULL(cameraDevices.size(), "No camera devices available");

	printf("Found: %d cameras\r\n", static_cast<int>(cameraDevices.size()));
	//for( auto iter : cameraDevices )
	{
		// start a capture session for each camera
		UniqueObj<CaptureSession> captureSession(iCameraProvider->createCaptureSession(cameraDevices[1], &status));
		EXIT_IF_NOT_OK(status, "Failed to createCaptureSession()");

		IEventProvider *iEventProvider = interface_cast<IEventProvider>(captureSession);
		EXIT_IF_NULL(iEventProvider, "iEventProvider is NULL");

		// these are the events we are interested
		std::vector<EventType> eventTypes;
		eventTypes.push_back(EVENT_TYPE_CAPTURE_STARTED);
		eventTypes.push_back(EVENT_TYPE_CAPTURE_COMPLETE);

		// create an event queue
		UniqueObj<EventQueue> queue(iEventProvider->createEventQueue(eventTypes));
		IEventQueue *iQueue = interface_cast<IEventQueue>(queue);
		EXIT_IF_NULL(iQueue, "event queue interface is NULL");

		ICaptureSession* iSession = interface_cast<ICaptureSession>(captureSession);
		EXIT_IF_NULL(iSession, "Cannot get ICaptureSession");

		printf("Testing capture\r\n");

		// create stream settings
		Argus::Status status = STATUS_OK;
		UniqueObj<OutputStreamSettings> streamSettings(iSession->createOutputStreamSettings());
		IOutputStreamSettings* iStreamSettings = interface_cast<IOutputStreamSettings>(streamSettings);
		EXIT_IF_NULL(iStreamSettings, "Cannot get OutputStreamSettings Interface");
		iStreamSettings->setPixelFormat(PIXEL_FMT_YCbCr_420_888);
		iStreamSettings->setResolution(Size2D<uint32_t>(1280, 1024));
		iStreamSettings->setMetadataEnable(true);

		// create a stream from the stream settings
		UniqueObj<OutputStream> stream(iSession->createOutputStream(streamSettings.get()));
		IStream *iStream = interface_cast<IStream>(stream);
		EXIT_IF_NULL(iStream, "Cannot get OutputStream Interface");

		// create a consumer for the stream
		UniqueObj<EGLStream::FrameConsumer> consumer(EGLStream::FrameConsumer::create(stream.get()));
		EGLStream::IFrameConsumer* iFrameConsumer = interface_cast<EGLStream::IFrameConsumer>(consumer);
		EXIT_IF_NULL(iFrameConsumer, "Failed to initialize Consumer");

		// create a capture request
		UniqueObj<Request> request(iSession->createRequest(CAPTURE_INTENT_STILL_CAPTURE));
		IRequest *iRequest = interface_cast<IRequest>(request);
		EXIT_IF_NULL(iRequest, "Failed to get capture request interface");

		IAutoControlSettings* iAutoControlSettings = interface_cast<IAutoControlSettings>(iRequest->getAutoControlSettings());
		EXIT_IF_NULL(iAutoControlSettings, "Failed to get IAutoControlSettings");

		status = iAutoControlSettings->setAeAntibandingMode( AE_ANTIBANDING_MODE_OFF);
		EXIT_IF_NOT_OK(status, "Failed to setAeAntibandingMode()");

		status = iAutoControlSettings->setAeLock(true);
		EXIT_IF_NOT_OK(status, "Failed to setAeLock()");

		status = iAutoControlSettings->setAwbLock(true);
		EXIT_IF_NOT_OK(status, "Failed to setAwbLock()");

		status = iAutoControlSettings->setExposureCompensation(0.0f);
		EXIT_IF_NOT_OK(status, "Failed to setExposureCompensation()");

		status = iAutoControlSettings->setIspDigitalGainRange(Range<float>(1.0f,1.0f));
		EXIT_IF_NOT_OK(status, "Failed to setIspDigitalGainRange()");

		ISourceSettings* iSourceSettings = interface_cast<ISourceSettings>(iRequest->getSourceSettings());
		EXIT_IF_NULL(iRequest, "Failed to get ISourceSettings");

		status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(6000000, 6000000));
		EXIT_IF_NOT_OK(status, "Failed to get setExposureTimeRange");

        status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(7000000, 8000000));
		EXIT_IF_NOT_OK(status, "Failed to get setExposureTimeRange");
		
		status = iSourceSettings->setGainRange(Range<float>(1.0f, 1.0f));
		EXIT_IF_NOT_OK(status, "Failed to get setGainRange");

		ISensorMode *iSensorMode = interface_cast<ISensorMode>(iSourceSettings->getSensorMode());
		EXIT_IF_NULL(iSensorMode, "Failed to get sensor mode interface");
		Argus::Size2D<uint32_t> sensorResolution = iSensorMode->getResolution();
		printf("Sensor resolution: %d x %d\r\n", sensorResolution.width(), sensorResolution.height() );

		// what is the range
		Range<uint64_t> range = iSourceSettings->getExposureTimeRange();
		printf("Exposure is set to: %lu ns to %lu ns\r\n", range.min(), range.max());

		// not really sure why we need to enable the output stream on the request....
		status = iRequest->enableOutputStream(stream.get());
		EXIT_IF_NOT_OK(status, "Failed to enable stream in capture request");
		
        while(1) 
        {
			// send a capture request
			uint32_t requestId = iSession->capture(request.get());
			printf("Capture request sent: %d\r\n", requestId);


			// receive the frame
			printf("Acquiring image...\r\n\r\n");
			UniqueObj<EGLStream::Frame> frame(iFrameConsumer->acquireFrame(5000000000, &status)); // 5 seconds in nanoseconds
			printf("Frame received!\r\n");
			EGLStream::IFrame *iFrame = interface_cast<EGLStream::IFrame>(frame);
			EXIT_IF_NULL(iFrame, "Failed to get IFrame interface");

			// wait for the capture event
			const uint64_t ONE_SECOND = 1000000000;
			iEventProvider->waitForEvents(queue.get(), 5*ONE_SECOND);

			uint64_t frameStartEventTime = 0;

			size_t queueSize = iQueue->getSize();
			printf("Event queue size: %d, expected: %d\r\n", (int)queueSize, 2);
			const Event* event = iQueue->getNextEvent();
			while(event) 
			{
				const IEvent* iEvent = interface_cast<const IEvent>(event);
				if(iEvent->getEventType() == EVENT_TYPE_CAPTURE_STARTED )
				{
					frameStartEventTime = iEvent->getTime();
					printf("Saw Capture Started Event at: %lu\r\n", frameStartEventTime);

				}
				else if(iEvent->getEventType() == EVENT_TYPE_CAPTURE_COMPLETE )
				{
					const IEventCaptureComplete* iEventCaptureComplete = interface_cast<const IEventCaptureComplete>(event);
					if( iEventCaptureComplete ) 
					{
						printf("Saw capture complete event at: %lu, status: %d\r\n", iEvent->getTime(), iEventCaptureComplete->getStatus());
						const CaptureMetadata *metaData = iEventCaptureComplete->getMetadata();
						const ICaptureMetadata* iMetadata = interface_cast<const ICaptureMetadata>(metaData);

						printf( "\tExposureTime: %lu ns\r\n"
								"\tReadout Time: %lu ns\r\n"
								"\tAnalog Gain: %f\r\n"
								"\tISP Gain: %f\r\n"
								"\tExposure locked: %d\r\n"
								"\tISO: %d\r\n"
								"\tSensor timestamp: %lu  ms\r\n"
								"\tTime delta between capture started and completed events: %lu ns\r\n",
								iMetadata->getSensorExposureTime(),
								iMetadata->getFrameReadoutTime(),
								iMetadata->getSensorAnalogGain(),
								iMetadata->getIspDigitalGain(),
								iMetadata->getAeLocked(),
								iMetadata->getSensorSensitivity(),
								iMetadata->getSensorTimestamp()/1000000,
								iEvent->getTime() - frameStartEventTime
						);
					}
					else
					{
						printf("EVENT_TYPE_CAPTURE_COMPLETE event is not type IEventCaptureComplete\r\n");
					}
				} 
				else
				{
					printf("Saw UNKNOWN event\r\n");
				}
				event = iQueue->getNextEvent();
			}

			EGLStream::Image *image = iFrame->getImage();
			EXIT_IF_NULL(image, "Failed to get Image from iFrame->getImage()");

			//EGLStream::IImageJPEG *iImageJPEG = interface_cast<EGLStream::IImageJPEG>(image);
			//EXIT_IF_NULL(iImageJPEG, "Failed to get ImageJPEG Interface");

			//printf("Saving image\r\n");
			//status = iImageJPEG->writeJPEG("image.jpg");
			//EXIT_IF_NOT_OK(status, "Failed to write JPEG");
			}
			captureSession.reset();
	}
}

when call following code:

status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(6000000, 6000000));
		EXIT_IF_NOT_OK(status, "Failed to get setExposureTimeRange");

        status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(7000000, 8000000));
		EXIT_IF_NOT_OK(status, "Failed to get setExposureTimeRange");

Sensor driver don’t see any ioctl call.

Hi Support,

Have any update on the issues?

I 'm still facing issues that the app can not set Exposure time and gain by Nvidia multimedia api.

Tried the following code to set ExposureTime and Gain value:

status = iSourceSetting->setExposureTimeRange(Range<uint64_t>(v1,v1));

status = iSourceSetting->setExposureTimeRange(Range<uint64_t>(v2,v2));

It seem the return status is OK, But it have no effect.

I will been appreciated to you if you can provide us usefully guide.

Thanks,
Martin

hello 27653276,

we found there’s issue that nvcamerasrc did not handle the exposure-time setting correctly, please refer to similar issue in Topic 1044552.
could you please replace the /usr/lib/aarch64-linux-gnu/gstreamer-1.0/libgstnvcamera.so for verification.

BTW, you could also change the property settings by specify exposure time with gstreamer plugins.
for example,

$ gst-launch-1.0 nvcamerasrc fpsRange="15 15" auto-exposure=1 wbmode=0 scene-mode=3 flicker=0 intent=3 wbManualMode=3 aeLock=true exposure-time=0.005 ! nvoverlaysink

Hi Jerry,

Our Application is based on sample “tegra_multimedia_api\samples\09_camera_jpeg_capture”,
Do you think it is related with /usr/lib/aarch64-linux-gnu/gstreamer-1.0/libgstnvcamera.so?

Thanks

hello 27653276,

okay, MMAPIs is not using a gstreamer framework.
I’ve couple of suggestions as below for you testing,

  1. could you please check your sensor device tree properties for the exposure time range capability.
  2. please share the debug prints of iSourceSettings->getExposureTimeRange(); before and after setting the exposure-time manually.

Hi Jerry,

Thank you for your kindly support!

Sensor device tree for the exposure time range:

mode0 { // SC130_MODE_3840X2160
						mclk_khz = "27000";
						num_lanes = "4";
						tegra_sinterface = "serial_e";
						discontinuous_clk = "yes";
						dpcm_enable = "false";
						cil_settletime = "0";
						
	                    csi_pixel_bit_depth = "10";
						active_w = "1280";
						active_h = "1024";
						pixel_t = "bayer_bggr";
						readout_orientation = "0";
						line_length = "1596";
						inherent_gain = "1";
						mclk_multiplier = "25";
						pix_clk_hz = "201600000";

						min_gain_val = "1.0";
						max_gain_val = "118.0";
						min_hdr_ratio = "1";
						max_hdr_ratio = "64";
						min_framerate = "20";
						max_framerate = "20";
						min_exp_time = "1000";
						max_exp_time = "40000";
				};

the debug print is as following:

LSC: LSC surface is not based on full res!
LSC: LSC surface is not based on full res!
PRODUCER: Creating output stream
PRODUCER: Launching consumer thread
CONSUMER: Waiting until producer is connected...
PRODUCER: Available Sensor modes :
PRODUCER: [0] W=1280 H=1024
PRODUCER: Requested FPS out of range. Fall back to 30
PRODUCER: Starting repeat capture requests.
CONSUMER: Producer has connected; continuing.
PRODUCER: getExposureTimeRange 2000 - 2000
SCF: Error InvalidState:  NonFatal ISO BW requested not set. Requested = 2147483647 Set = 4687500 (in src/services/power/PowerServiceCore.cpp, function setCameraBw(), line 653)
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
PRODUCER: getExposureTimeRange 2000 - 2000
PRODUCER: getExposureTimeRange 30000 - 30000
CONSUMER: Done.
PRODUCER: Done -- exiting.

the test code:

while(i++ < 10)
	{
	Range<uint64_t> sensorExposureTimeRange ;
    status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(2000, 2000));
	if(status !=STATUS_OK ) ORIGINATE_ERROR("Failed to setExposureTimeRange()");
	usleep(3000);
	sensorExposureTimeRange = iSourceSettings->getExposureTimeRange();
	PRODUCER_PRINT("getExposureTimeRange %ld - %ld\n",sensorExposureTimeRange.min(),sensorExposureTimeRange.max());
	sleep(CAPTURE_TIME);
	status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(30000, 30000));
	if(status !=STATUS_OK ) ORIGINATE_ERROR("Failed to setExposureTimeRange()");
	usleep(3000);
	sensorExposureTimeRange = iSourceSettings->getExposureTimeRange();
	PRODUCER_PRINT("getExposureTimeRange %ld - %ld\n",sensorExposureTimeRange.min(),sensorExposureTimeRange.max());
	sleep(CAPTURE_TIME);
    }

When running the above test code on change ExposureTimeRange, I don’t see any call on sensor driver layer.

Thanks

hello 27653276,

because you’re setting the exposure time out of sensor driver support capability.
please check Sensor Driver Programming Guide, the min_exp_time and max_exp_time properties define it with microseconds.

according to your device tree settings, your sensor exposure time capability is between 1ms to 40ms.

however, you should check L4T Multimedia API Reference, the units of ISourceSettings::setExposureTimeRange function is based-on nanoseconds.
both of your sensor settings setExposureTimeRange(2000)= 0.002ms and setExposureTimeRange(30000)=0.03ms were below the sensor capability.
software side would skip these illegal controls and keep using default settings, that’s why you don’t see the ioctls from sensor driver side.
thanks

Hi Jerry,

Sorry, I didn't read your document carefully.

Sensor Driver Programming Guide said "Specifies the minimum exposure time limit for the mode, in [b]microseconds[/b]"

my device tree settings define:      
min_exp_time = "1000";
max_exp_time = "40000";
Do you confirm exposure time capability is between 1ms to 40ms?
By my understandm that's should been 1000ms to 40000ms, Correctly?

Thanks

hello 27653276,

microseconds represent 10^-6, the unit is μs.
milliseconds represent 10^-3, the unit is ms.

hence,
your min_exp_time=1000μs, then having simple calculation it shows 1ms.
also, the max_exp_time=40000μs means 40ms.

Hi Jerry,

Ok, Thank you for helping me to point out my wrong understanding.
Then update to code to here:

uint64_t k;
   k = 1000000;
   status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(5*k, 5*k));//means 5ms 
   status = iSourceSettings->setExposureTimeRange(Range<uint64_t>(20*k, 20*k));//means 20ms

Unfortunately,still not see the ioctl in the sensor driver.

Also, There are also exposure param define in sensor driver.

Let me show you the define:

#define SC130GS_MIN_EXPOSURE_COARSE (10)
#define SC130GS_MAX_EXPOSURE_COARSE (9000000000)

Can you let me know what’s the units?

Also, Can we enable more debug print in the tegra_multimedia_api to see what’s happen?

Thanks

hello 27653276,

that’s coarse integration time,
you may check Sensor Driver Programming Guide for the calculation formulas, or you might contact with your sensor vendor for more details.
thanks