Stream Bayer Data with Gtsreamer

You may try the following :

1. Build a RG10 to rggb converter

You would create a file bayer10_8.c with the following content:

#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

int main (int argc, char** argv) 
{       
	char filename[64];

	int readItems;
	int width, height, size;
	unsigned int curLevel, curItem; 
	unsigned short *sbuf;
	unsigned char *cbuf;
	unsigned int curFrame = 0;
	bool bRun = true;
	
	if (argc < 3) {
		fprintf(stderr, "Usage: bayer10_8 width height [any 3rd arg for saving to files in out directory to be created beforehand]\n");
		return -1;
	}
	width = atoi(argv[1]);
	if (width < 1) {
	   fprintf(stderr, "Error bad width\n");
	   return -2;
	}
	height = atoi(argv[2]);
	if (height < 1) {
	   fprintf(stderr, "Error bad height\n");
	   return -3;
	}
	size = width*height;

	sbuf = malloc(2*size);
	if (!sbuf) {
		fprintf(stderr, "Error failed to allocate sbuf.");
		return -4;
	}
	cbuf = malloc(size);
	if (!sbuf) {
		fprintf(stderr, "Error failed to allocate cbuf.");
		return -5;
	}

	while(bRun) {
		curLevel = 0;
		while (curLevel < size) {
			readItems = fread(sbuf, 2, size - curLevel, stdin);
			if (readItems < 1) {
				bRun = false;
				break;
			}
			for (curItem=curLevel; curItem < curLevel + readItems; ++curItem)
				cbuf[curItem] = (unsigned char)(sbuf[curItem]>>6);
			curLevel += readItems;
		}
		if (!bRun)
			break;
			
		if (argc > 3) {
			sprintf(filename, "out/frame_%dx%d_%05d.rggb", width, height, curFrame);
			FILE* fout = fopen(filename, "wb");
			if (!fout) {
				fprintf(stderr, "Error: failed to open file %s for writing.\nDid you create out folder ?\n", filename);
				return -6;
			}
			fwrite(cbuf, size, 1, fout);
			fclose(fout);
		}
		else
			fwrite(cbuf, 1, size, stdout);
		++curFrame;
	}
	free(sbuf);
	free(cbuf);
	return 0;
}

Here shifting 6 bits to right according to this,

and build with:

gcc -Wall -O3 -o bayer10_8 bayer10_8.c

The converter will output into stdout if launched with only two args.
Adding more args would make it output separate rggb files for each frame into out folder to be created beforehand.

2. Set your sensor mode from Argus:

# Set 1280x720@60
gst-launch-1.0 nvarguscamerasrc sensor-mode=4 num-buffers=1 ! 'video/x-raw(memory:NVMM),width=1280,height=720,framerate=60/1' ! fakesink 

3. Preview: debayer and display with gstreamer:

v4l2-ctl -d /dev/video0 --set-ctrl=bypass_mode=0,sensor_mode=4 --set-fmt-video=width=1280,height=720,pixelformat=RG10 --stream-mmap --stream-to=- | ./bayer10_8 1280 720 | gst-launch-1.0 -q filesrc location=/dev/stdin blocksize=$(expr 1280 \* 720) ! video/x-bayer,format=rggb,width=1280,height=720,framerate=60/1 ! queue ! bayer2rgb ! queue ! videoconvert ! xvimagesink

4. Try a capture into images:

Be aware that it can fill your disk very quickly. Better save to an external disk, or stop with Ctrl-C after a few seconds.

# Create out folder in not yet done
mkdir out

# Or clean folder if it exists
rm out/*

# Run a capture with 1280x720@60 fps... 
v4l2-ctl -d /dev/video0 --set-ctrl=bypass_mode=0,sensor_mode=4 --set-fmt-video=width=1280,height=720,pixelformat=RG10 --stream-mmap --stream-to=- | ./bayer10_8 1280 720 f

# Stop with Ctrl-C

# Check for created files
ls out/*

5. Note for manually adjusting gain or exposure

For adjusting gain or exposure, you would have to activate override_enable control.
However, it may not work as long as you’ve not run argus yet, but this would have been done in step 2.
Then you may be able to set your values :

v4l2-ctl -d /dev/video0 --set-ctrl=bypass_mode=0,gain=50,exposure=5000,frame_rate=60000000,sensor_mode=4,override_enable=1 --set-fmt-video=width=1280,height=720,pixelformat=RG10 --stream-mmap --stream-to=- | ./bayer10_8 1280 720 | gst-launch-1.0 -q filesrc location=/dev/stdin blocksize=$(expr 1280 \* 720) ! video/x-bayer,format=rggb,width=1280,height=720,framerate=60/1 ! queue ! bayer2rgb ! videoconvert ! xvimagesink

6. Streaming bayer 8 bits rggb as gray8 and storing on receiver side

There is no support for streaming bayer video that I’m aware of, but for your case it is possible to cheat and pretend it is GRAY8 format while it is actually bayer rggb format. For that you would try:

Sender:

v4l2-ctl -d /dev/video0 --set-ctrl=bypass_mode=0,sensor_mode=4 --set-fmt-video=width=1280,height=720,pixelformat=RG10 --stream-mmap --stream-to=- | ./bayer10_8 1280 720 | gst-launch-1.0 -q filesrc location=/dev/stdin blocksize=$(expr 1280 \* 720) do-timestamp=1 ! queue ! video/x-raw,format=GRAY8,width=1280,height=720,framerate=60/1 ! matroskamux streamable=1 ! tcpserversink sync=0

Receiver:

gst-launch-1.0 tcpclientsrc ! queue ! matroskademux ! multifilesink location=frame_received_%05d.rggb

This is for local (Jetson) testing,

Obviously you would adjust host and port properties for your case (assuming that no firewall blocks TCP port 4593):
Sender:

v4l2-ctl -d /dev/video0 --set-ctrl=bypass_mode=0,sensor_mode=4 --set-fmt-video=width=1280,height=720,pixelformat=RG10 --stream-mmap --stream-to=- | ./bayer10_8 1280 720 | gst-launch-1.0 -q filesrc location=/dev/stdin blocksize=$(expr 1280 \* 720) do-timestamp=1 ! queue ! video/x-raw,format=GRAY8,width=1280,height=720,framerate=60/1 ! matroskamux streamable=1 ! tcpserversink host=<Jetson_IP> sync=0

Receiver:

gst-launch-1.0 tcpclientsrc host=<Jetson_IP> ! queue ! matroskademux ! multifilesink location=frame_received_%05d.rggb

7. Streaming Bayer 10 bits as gray16 would require twice bandwidth

Though, this can be achieved with a different converter to 16 bits bayer LE format with a 1 Gb/s wired ethernet.

bayer10_16le_10bpp.c
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

int main (int argc, char** argv) 
{       
	char filename[64];

	int readItems;
	int width, height, size;
	unsigned int curLevel, curItem; 
	unsigned short *sin_buf, *sout_buf;
	unsigned int curFrame = 0;
	bool bRun = true;
	
	if (argc < 3) {
		fprintf(stderr, "Usage: bayer10_8 width height [any 3rd arg for saving to files in out directory to be created beforehand]\n");
		return -1;
	}
	width = atoi(argv[1]);
	if (width < 1) {
	   fprintf(stderr, "Error bad width\n");
	   return -2;
	}
	height = atoi(argv[2]);
	if (height < 1) {
	   fprintf(stderr, "Error bad height\n");
	   return -3;
	}
	size = width*height;

	sin_buf = malloc(2*size);
	if (!sin_buf) {
		fprintf(stderr, "Error failed to allocate sin_buf.");
		return -4;
	}
	sout_buf = malloc(2*size);
	if (!sout_buf) {
		fprintf(stderr, "Error failed to allocate sout_buf.");
		return -5;
	}

	while(bRun) {
		curLevel = 0;
		while (curLevel < size) {
			readItems = fread(sin_buf, 2, size - curLevel, stdin);
			if (readItems < 1) {
				bRun = false;
				break;
			}
			for (curItem=curLevel; curItem < curLevel + readItems; ++curItem)
				sout_buf[curItem] = (sin_buf[curItem]>>4);
			curLevel += readItems;
		}
		if (!bRun)
			break;
			
		if (argc > 3) {
			sprintf(filename, "out/frame_%dx%d_%05d.rggb", width, height, curFrame);
			FILE* fout = fopen(filename, "wb");
			if (!fout) {
				fprintf(stderr, "Error: failed to open file %s for writing.\nDid you create out folder ?\n", filename);
				return -6;
			}
			fwrite(sout_buf, 2, size, fout);
			fclose(fout);
		}
		else
			fwrite(sout_buf, 2, size, stdout);
		++curFrame;
	}
	free(sin_buf);
	free(sout_buf);
	return 0;
}

This may be dark depending on how you’re debayering. You may also try full 16 bits scale with:

bayer10_16le.c
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

int main (int argc, char** argv) 
{       
	char filename[64];

	int readItems;
	int width, height, size;
	unsigned int curLevel, curItem; 
	unsigned short *sin_buf, *sout_buf;
	unsigned int curFrame = 0;
	bool bRun = true;
	
	if (argc < 3) {
		fprintf(stderr, "Usage: bayer10_8 width height [any 3rd arg for saving to files in out directory to be created beforehand]\n");
		return -1;
	}
	width = atoi(argv[1]);
	if (width < 1) {
	   fprintf(stderr, "Error bad width\n");
	   return -2;
	}
	height = atoi(argv[2]);
	if (height < 1) {
	   fprintf(stderr, "Error bad height\n");
	   return -3;
	}
	size = width*height;

	sin_buf = malloc(2*size);
	if (!sin_buf) {
		fprintf(stderr, "Error failed to allocate sin_buf.");
		return -4;
	}
	sout_buf = malloc(2*size);
	if (!sout_buf) {
		fprintf(stderr, "Error failed to allocate sout_buf.");
		return -5;
	}

	while(bRun) {
		curLevel = 0;
		while (curLevel < size) {
			readItems = fread(sin_buf, 2, size - curLevel, stdin);
			if (readItems < 1) {
				bRun = false;
				break;
			}
			for (curItem=curLevel; curItem < curLevel + readItems; ++curItem)
				sout_buf[curItem] = ((sin_buf[curItem]>>4)<<8);
			curLevel += readItems;
		}
		if (!bRun)
			break;
			
		if (argc > 3) {
			sprintf(filename, "out/frame_%dx%d_%05d.rggb", width, height, curFrame);
			FILE* fout = fopen(filename, "wb");
			if (!fout) {
				fprintf(stderr, "Error: failed to open file %s for writing.\nDid you create out folder ?\n", filename);
				return -6;
			}
			fwrite(sout_buf, 2, size, fout);
			fclose(fout);
		}
		else
			fwrite(sout_buf, 2, size, stdout);
		++curFrame;
	}
	free(sin_buf);
	free(sout_buf);
	return 0;
}

and build as:

gcc -Wall -O3 -o bayer10_16 bayer10_16le.c

# or
gcc -Wall -O3 -o bayer10_16 bayer10_16le_10bpp.c

Then just stream with:

v4l2-ctl -d /dev/video0 --set-ctrl=bypass_mode=0,sensor_mode=4 --set-fmt-video=width=1280,height=720,pixelformat=RG10 --stream-mmap --stream-to=- | ./bayer10_16 1280 720 | gst-launch-1.0 -q filesrc location=/dev/stdin blocksize=$(expr 1280 \* 720 \* 2) do-timestamp=1 ! queue ! video/x-raw,format=GRAY16_LE,width=1280,height=720,framerate=60/1 ! multipartmux ! tcpserversink host=<Jetson_IP> sync=0

and receive with:

gst-launch-1.0 tcpclientsrc host=<Jetson_IP> ! multipartdemux single-stream=1 ! video/x-raw,fromat=GRAY16_LE,width=1280,height=720,framerate=60/1 ! multifilesink location=<wherever_you_have_room_for_that>/frame_1280x720_%05d.rggb16le