Pilote de périphérique pour les programmes et le matériel s'exécutant dans l'espace utilisateur sous Linux pour partager la mémoire (V4L2_MEMORY_USERPTR)

introduction

L'auteur publie udmabuf en open source.

Cet article décrit comment utiliser le tampon alloué par udmabuf en tant que tampon V4L2.

Contexte

Dans l'article suivant, j'ai montré le problème que le cache n'est pas activé lors de la mmaping du tampon V4L2 avec le pilote V4L2 en utilisant Xilinx VDMA, etc.

En guise de contre-mesure, au lieu de V4L2_MEMORY_MMAP, vous pouvez allouer un tampon côté application utilisateur et le transmettre au pilote V4L2 avec V4L2_MEMORY_USERPTR. Cependant, les forums Xilinx ont montré que cette méthode ne fonctionne pas.

Cela est évident quand on y pense, car Xilinx VDMA ne prend pas en charge le Scatter Gather, donc le tampon V4L2 doit être contigu en mémoire physique. Si vous allouez un tampon dans l'espace utilisateur, il n'y a aucune garantie qu'il sera contigu dans la mémoire physique. Je suis resté coincé dans ce chèque.

On a donc essayé d'utiliser udmabuf pour sécuriser un tampon contigu dans la mémoire physique, en mappant ce tampon à l'espace utilisateur avec mmap et en le passant au pilote V4L2 avec V4L2_MEMORY_USERPTR. Malheureusement, cela n'a pas fonctionné au début et j'ai donné un problème à udmabuf.

En fin de compte, cette tentative semble avoir réussi. Il a fallu 24 ms pour que V4L2_MEMORY_MMAP transfère les données d'image 1920 x 1080p NV12, mais il a fallu 1,6 ms pour udmabuf + V4L2_MEMORY_USERPTR.

Exemple d'utilisation

Ici, nous expliquerons comment utiliser le tampon alloué par udmabuf comme tampon V4L2 en nous basant sur un exemple.

Préparer udmabuf

udmabuf est un module du noyau Linux. Pour créer et installer udmabuf, reportez-vous aux documents tels que Readm.md de udmabuf.

udmabuf ouvert

Ouvrez udmabuf.

udmabuf.hpp


	name  = device_name;
	sprintf(file_name, "/dev/%s", name.c_str());
	if ((_device_file = open(file_name, O_RDWR)) < 0) {
 		printf("Can not open %s\\n", file_name);
		_status = false;
		goto done;
	}

udmabuf mmap

Mappez udmabuf à l'espace utilisateur avec mmap.

udmabuf.hpp


	buf = mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, _device_file, 0);
	if (buf == MAP_FAILED) {
		printf("Can not mmap %s\\n", file_name);
		_status = false;
		goto done;
	}

Effacer udmabuf

En fait, ce processus est très important et indispensable. En effet, udmabuf mappe la mémoire physique sur des adresses virtuelles via la pagination à la demande. Pour élaborer un peu plus, udmabuf ne mappe pas immédiatement la mémoire physique aux adresses virtuelles avec mmap (). Lorsque vous accédez à une adresse virtuelle, une erreur de page se produit si la mémoire physique n'est pas mappée. udmabuf ne mappe la mémoire physique que lorsqu'une erreur de page se produit.

Dans le cas d'udmabuf, l'adresse virtuelle retournée par mmap () n'a pas encore été mappée à une adresse physique, donc si vous passez cette adresse virtuelle à un périphérique V4L2, comme indiqué dans [Buffer from UDMABUF and V4L2_MEMORY_USERPTR # 38] Erreur se produit.

Pour éviter cela, il est judicieux de vider le tampon immédiatement après mMap (). En écrivant dans le tampon, cela provoque une erreur de page et mappe la mémoire physique à l'adresse virtuelle.

udmabuf.hpp


	// Write once to allocate physical memory to u-dma-buf virtual space.
	// Note: Do not use memset() for this.
	//       Because it does not work as expected.
	{
		uint64_t*	word_ptr = reinterpret_cast<uint64_t*>(buf);
		size_t    	words    = buf_size/sizeof(uint64_t);
		for(int i = 0 ; i < words; i++) {
			word_ptr[i] = 0;
		}
	}

N'utilisez pas memset () pour effacer le tampon. memset () fait des choses très compliquées et je ne peux pas obtenir les résultats que je souhaite.

À l'avenir, nous envisageons de le faire dans udmabuf. Jusque-là, effacez explicitement le tampon comme dans ce cas d'utilisation.

Demande de tampon V4L2 au pilote V4L2

Demandez un tampon V4L2 pour le pilote V4L2. Ce faisant, spécifiez V4L2_MEMORY_USERPTR pour req.memory pour indiquer que le tampon V4L2 sera alloué par le programme utilisateur plutôt que par le pilote V4L2.

example.cpp


	v4l2_requestbuffers req ;
	memset(&req, 0, sizeof(req));
	req.count = num_buf;
	req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	req.memory = V4L2_MEMORY_USERPTR;
	ret = xioctl(fd, VIDIOC_REQBUFS, &req);
	if (ret < 0) {
		perror("ioctl(VIDIOC_REQBUFS)");
		return -1;
	}

Mettre en file d'attente le tampon V4L2 vers le pilote V4L2

Mettez le tampon V4L2 en file d'attente dans la file d'attente du pilote V4L2 avant de démarrer la diffusion. L'adresse virtuelle qui mappe la mémoire physique du tampon alloué par udmabuf est définie dans buf.m.userptr.

example.cpp


	for (i = 0; i < num_buf; i++) {
		v4l2_buffer buf;
		memset(&buf, 0, sizeof(buf));
		buf.type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_USERPTR;
		buf.index = i;
		buf.length = buf_size;
		buf.m.userptr = reinterpret_cast<unsigned long>(udmabuf.buf + i*buf_size);
		ret = xioctl(fd, VIDIOC_QBUF, &buf);
		if (ret < 0) {
			perror("ioctl(VIDIOC_QBUF)");
			return -1;
		}
	}

référence

["Pilote de périphérique pour les programmes s'exécutant dans l'espace utilisateur sur Linux et la mémoire de partage matériel" @Qiita]: https://qiita.com/ikwzm/items/cc1bb33ff43a491440ea "" Programmes s'exécutant dans l'espace utilisateur sous Linux Pilote de périphérique pour le matériel pour partager la mémoire avec @Qiita " ["Problème avec aucune performance avec les E / S de streaming V4L2 (V4L2_MEMORY_MMAP)" @Qiita]: https://qiita.com/ikwzm/items/8f1c98efe6fd4ae2490a "Aucune performance avec les E / S de streaming V4L2 (V4L2_MEMORY_MMAP)" 』@Qiita" [『V4l2 V4L2_MEMORY_USERPTR:contiguous mapping is too small 4096/1228800』]: https://forums.xilinx.com/t5/Embedded-Linux/V4l2-V4L2-MEMORY-USERPTR-contiguous-mapping-is-too-small-4096/td-p/825067 "『V4l2 V4L2_MEMORY_USERPTR:contiguous mapping is too small 4096/1228800』@XilinxForum" [『Buffer from UDMABUF and V4L2_MEMORY_USERPTR #38』]: https://github.com/ikwzm/udmabuf/issues/38 "『Buffer from UDMABUF and V4L2_MEMORY_USERPTR #38』@gitub.com"

Recommended Posts

Pilote de périphérique pour les programmes et le matériel s'exécutant dans l'espace utilisateur sous Linux pour partager la mémoire (V4L2_MEMORY_USERPTR)
Pilote de périphérique (compatible NumPy) pour les programmes et le matériel qui s'exécutent dans l'espace utilisateur sous Linux pour partager la mémoire
Ajouter des mots au dictionnaire utilisateur de MeCab sur Ubuntu pour une utilisation en Python