Jetson multimedia api "17_frontend" sample VideoEncoder class usage

Hello,

I am trying to write a simple h264 encoder with jetson multimedia api. In the “frontend” sample, there is a convenience class VideoEncoder, that seems simple to use. However, I don’t quite understand how to use the encodeFromFd function. In the sample it is managed with custom Argus frames, but the implementation is not available. So far I’ve been trying to encode cv::Mat camera frames like so:

static void callback(int dmabuf_fd, void* arg)
{
	std::cout << "buf done" << std::endl;
}

int main() {

	VideoEncoder encoder("myenc", "out.h264", 1920, 1080, V4L2_PIX_FMT_H264);
	encoder.setBufferDoneCallback(callback, nullptr);

	encoder.initialize();

	cv::VideoCapture cap("/dev/video0");
	if (!cap.isOpened()) {
		std::cerr << "Error: Could not open the camera." << std::endl;
		return -1;
	}

	cv::Mat image;
	
	while (true) {
		cap >> image;
		if (image.empty()) {
			std::cerr << "Error: Captured empty frame." << std::endl;
			continue;
		}

		NvBufSurf::NvCommonAllocateParams input_params = { 0 };
		input_params.memType = NVBUF_MEM_SURFACE_ARRAY;
		input_params.width = 1920;
		input_params.height = 1080;
		input_params.layout = NVBUF_LAYOUT_BLOCK_LINEAR;
		input_params.colorFormat = NVBUF_COLOR_FORMAT_NV12;
		input_params.memtag = NvBufSurfaceTag_NONE;

		int bufn = 0;

		if (NvBufSurf::NvAllocate(&input_params, 1, &bufn) < 0)
		{
			std::cout << "Failed to create nvbuffer!" << std::endl;
			return -1;
		}

		NvBufSurface* nvbuf_surface = nullptr;
		if (NvBufSurfaceFromFd(bufn, (void**)&nvbuf_surface) != 0) {
			std::cerr << "Error: Failed to map dmabuf_fd to NvBufSurface" << std::endl;
			return -1;
		}

		memcpy(nvbuf_surface->surfaceList[0].dataPtr, image.data, image.total() * image.elemSize());

		if (encoder.encodeFromFd(bufn)) {
			std::cout << "success_" << std::endl;
		}
	}

	cap.release();
	cv::destroyAllWindows();

	return 0;
}

The first frame is encoded fine, but then I get segfaults when trying to allocate another buffer. Buffer done callback is also never reached. Is the issue the incorrect image format or buffer handling? Thanks guys, I’m really struggling

Hi,
Please run the command and share the prints for reference:

$ v4l2-ctl -d /dev/video0 --list-formats-ext

Would like to know what formats the v4l2 source supports.

Hello, here’s the output:

ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'UYVY' (UYVY 4:2:2)
                Size: Discrete 640x480
                        Interval: Discrete 0.017s (60.000 fps)
                Size: Discrete 960x540
                        Interval: Discrete 0.017s (58.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.022s (45.000 fps)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.033s (30.000 fps)
        [1]: 'NV16' (Y/CbCr 4:2:2)
                Size: Discrete 640x480
                        Interval: Discrete 0.017s (60.000 fps)
                Size: Discrete 960x540
                        Interval: Discrete 0.017s (58.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.022s (45.000 fps)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.033s (30.000 fps)

Hi,
Please try the sample to capture UYVY data:

/usr/src/jetson_multimedia_api/samples/12_camera_v4l2_cida

And then apply the patch to encode to H264:
How to use v4l2 to capture videos in Jetson Orin r35 Jetpack 5.0 and encode them using a hardware encoding chip - #8 by DaneLLL

You may also follow FAQ and try gstreamer commands:
Jetson AGX Orin FAQ

Thank you for response.

Does it matter that the patch is for Jetpack 5.0, and I’m using 6.0?

Hi,
It should be good to apply the patch to Jetpack 6.

Thanks, Daniel.

With this patch it’s pretty comprehensive how to achieve what I wanted. However after further research I am wondering why would I not just use gstreamer. It handles everything in dma buffers (camera capture+encoding+streaming) and does not need to copy anything to cpu at any point. Am I right in thinking that? Or is there something that i’m missing?

Hi,
Yes, you can use gstreamer. We support jetson_multimedia_api and gstreamer. You can refer to the examples and give it a try:

Accelerated GStreamer — NVIDIA Jetson Linux Developer Guide