Re: Question about 'Generic V4L2 Andriod camera HAL' slide

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I suspect it was about a mem-to-mem test program originally written
by Pawel Osciak: https://linuxtv.org/patch/2187

I've attached a little bit updated version I used recently for testing
some changes at the v4l2-mem2mem kernel module.

You can also find some more test programs here:
http://git.infradead.org/users/kmpark/public-apps/tree

Regards,
Sylwester

On 12/31/2013 01:36 AM, m silverstri wrote:
Hi,

I google and find the presentation for Generic V4L2 Andriod camera
HAL, in there it said

* "A VEU mem2mem driver has been written to convert YUV camera output
to a 16-bit RGB format"
and
* "A test program from Sylwester has been xed and extended."

Can you please tell me where I can find the test program from Sylwester?

Thank you.
Mike
/**
 * process-vmalloc.c
 * Capture+output (process) V4L2 device tester.
 *
 * Pawel Osciak, p.osciak@xxxxxxxxxxx
 * 2009, Samsung Electronics Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <errno.h>

#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <stdint.h>

#include <linux/fb.h>
#include <linux/videodev2.h>

#include <sys/mman.h>

#define V4L2_CID_TRANS_TIME_MSEC        (V4L2_CID_PRIVATE_BASE)
#define V4L2_CID_TRANS_NUM_BUFS         (V4L2_CID_PRIVATE_BASE + 1)

#define VIDEO_DEV_NAME	"/dev/video0"
#define FB_DEV_NAME	"/dev/fb0"
#define NUM_BUFS	4
#define NUM_FRAMES	16

#define perror_exit(cond, func)\
	if (cond) {\
		fprintf(stderr, "%s:%d: ", __func__, __LINE__);\
		perror(func);\
		exit(EXIT_FAILURE);\
	}

#define error_exit(cond, func)\
	if (cond) {\
		fprintf(stderr, "%s:%d: failed\n", func, __LINE__);\
		exit(EXIT_FAILURE);\
	}

#define perror_ret(cond, func)\
	if (cond) {\
		fprintf(stderr, "%s:%d: ", __func__, __LINE__);\
		perror(func);\
		return ret;\
	}

#define memzero(x)\
	memset(&(x), 0, sizeof (x));

#define PROCESS_DEBUG 1
#ifdef PROCESS_DEBUG
#define debug(msg, ...)\
	fprintf(stderr, "%s: " msg, __func__, ##__VA_ARGS__);
#else
#define debug(msg, ...)
#endif

static int vid_fd, fb_fd;
static void *fb_addr;
static char *p_src_buf[NUM_BUFS], *p_dst_buf[NUM_BUFS];
static size_t src_buf_size[NUM_BUFS], dst_buf_size[NUM_BUFS];
static uint32_t num_src_bufs = 0, num_dst_bufs = 0;

/* Command-line params */
int initial_delay = 0;
int fb_x, fb_y, width, height;
int translen = 1;
/* For displaying multi-buffer transaction simulations, indicates current
 * buffer in an ongoing transaction */
int curr_buf = 0;
int transtime = 1000;
int num_frames = 0;
off_t fb_off, fb_line_w, fb_buf_w;
struct fb_var_screeninfo fbinfo;

static void init_video_dev(void)
{
	int ret;
	struct v4l2_capability cap;
	struct v4l2_format fmt;
	struct v4l2_control ctrl;

	vid_fd = open(VIDEO_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
	perror_exit(vid_fd < 0, "open");

	ctrl.id = V4L2_CID_TRANS_TIME_MSEC;
	ctrl.value = transtime;
	ret = ioctl(vid_fd, VIDIOC_S_CTRL, &ctrl);
	perror_exit(ret != 0, "ioctl");

	ctrl.id = V4L2_CID_TRANS_NUM_BUFS;
	ctrl.value = translen;
	ret = ioctl(vid_fd, VIDIOC_S_CTRL, &ctrl);
	perror_exit(ret != 0, "ioctl");

	ret = ioctl(vid_fd, VIDIOC_QUERYCAP, &cap);
	perror_exit(ret != 0, "ioctl");

	if (!(cap.capabilities & V4L2_CAP_VIDEO_M2M)) {
		fprintf(stderr, "Device does not support mem-to-mem\n");
		exit(EXIT_FAILURE);
	}

	/* Set format for capture */
	fmt.type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	fmt.fmt.pix.width	= width;
	fmt.fmt.pix.height	= height;
	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565X;
	fmt.fmt.pix.field	= V4L2_FIELD_ANY;

	ret = ioctl(vid_fd, VIDIOC_S_FMT, &fmt);
	perror_exit(ret != 0, "ioctl");

	/* The same format for output */
	fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
	fmt.fmt.pix.width	= width;
	fmt.fmt.pix.height	= height;
	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565X;
	fmt.fmt.pix.field	= V4L2_FIELD_ANY;

	ret = ioctl(vid_fd, VIDIOC_S_FMT, &fmt);
	perror_exit(ret != 0, "ioctl");
}

static void gen_src_buf(void *p, size_t size)
{
	uint8_t val;

	val = rand() % 256;
	memset(p, val, size);
}

static void gen_dst_buf(void *p, size_t size)
{
	/* White */
	memset(p, 255, 0);
}

static int read_frame(int last)
{
	struct v4l2_buffer buf;
	int ret;
	int j;
	char * p_fb = fb_addr + fb_off;

	memzero(buf);

	buf.type	= V4L2_BUF_TYPE_VIDEO_OUTPUT;
	buf.memory	= V4L2_MEMORY_MMAP;

	debug("Dequeuing source buffer...\n");
	ret = ioctl(vid_fd, VIDIOC_DQBUF, &buf);
	debug("Dequeued source buffer, index: %d\n", buf.index);
	if (ret) {
		switch (errno) {
		case EAGAIN:
			debug("Got EAGAIN\n");
			return 0;

		case EIO:
			debug("Got EIO\n");
			return 0;

		default:
			perror("ioctl");
			return 0;
		}
	}

	/* Verify we've got a correct buffer */
	assert(buf.index < num_src_bufs);

	/* Enqueue back the buffer (note that the index is preserved) */
	if (!last) {
		gen_src_buf(p_src_buf[buf.index], src_buf_size[buf.index]);
		buf.type	= V4L2_BUF_TYPE_VIDEO_OUTPUT;
		buf.memory	= V4L2_MEMORY_MMAP;
		ret = ioctl(vid_fd, VIDIOC_QBUF, &buf);
		perror_ret(ret != 0, "ioctl");
	}


	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	debug("Dequeuing destination buffer\n");
	ret = ioctl(vid_fd, VIDIOC_DQBUF, &buf);
	if (ret) {
		switch (errno) {
		case EAGAIN:
			debug("Got EAGAIN\n");
			return 0;

		case EIO:
			debug("Got EIO\n");
			return 0;

		default:
			perror("ioctl");
			return 1;
		}
	}
	debug("Dequeued dst buffer, index: %d\n", buf.index);
	/* Verify we've got a correct buffer */
	assert(buf.index < num_dst_bufs);

	debug("Current buffer in the transaction: %d\n", curr_buf);
	p_fb += curr_buf * (height / translen) * fb_line_w;
	++curr_buf;
	if (curr_buf >= translen)
		curr_buf = 0;

	/* Display results */
	for (j = 0; j < height / translen; ++j) {
		memcpy(p_fb, (void *)p_dst_buf[buf.index], fb_buf_w);
		p_fb += fb_line_w;
	}

	/* Enqueue back the buffer */
	if (!last) {
		gen_dst_buf(p_dst_buf[buf.index], dst_buf_size[buf.index]);
		ret = ioctl(vid_fd, VIDIOC_QBUF, &buf);
		perror_ret(ret != 0, "ioctl");
		debug("Enqueued back dst buffer\n");
	}

	return 0;
}

void init_usage(int argc, char *argv[])
{
	if (argc != 9) {
		printf("Usage: %s initial_delay bufs_per_transaction "
			"trans_length_msec num_frames fb_offset_x fb_offset_y "
			"width height\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	initial_delay = atoi(argv[1]);
	translen = atoi(argv[2]);
	transtime = atoi(argv[3]);
	num_frames = atoi(argv[4]);
	fb_x = atoi(argv[5]);
	fb_y = atoi(argv[6]);
	width = atoi(argv[7]);
	height = atoi(argv[8]);
	debug("NEW PROCESS: fb_x: %d, fb_y: %d, width: %d, height: %d, "
		"translen: %d, transtime: %d, num_frames: %d\n",
		fb_x, fb_y, width, height, translen, transtime, num_frames);
}

void init_fb(void)
{
	int ret;
	size_t map_size;

	fb_fd = open(FB_DEV_NAME, O_RDWR, 0);
	perror_exit(fb_fd < 0, "open");

	ret = ioctl(fb_fd, FBIOGET_VSCREENINFO, &fbinfo);
	perror_exit(ret != 0, "ioctl");
	debug("fbinfo: xres: %d, xres_virt: %d, yres: %d, yres_virt: %d\n",
		fbinfo.xres, fbinfo.xres_virtual,
		fbinfo.yres, fbinfo.yres_virtual);

	fb_line_w= fbinfo.xres_virtual * (fbinfo.bits_per_pixel >> 3);
	fb_off = fb_y * fb_line_w + fb_x * (fbinfo.bits_per_pixel >> 3);
	fb_buf_w = width * (fbinfo.bits_per_pixel >> 3);
	map_size = fb_line_w * fbinfo.yres_virtual;

	fb_addr = mmap(0, map_size, PROT_WRITE | PROT_READ,
			MAP_SHARED, fb_fd, 0);
	perror_exit(fb_addr == MAP_FAILED, "mmap");
}

int main(int argc, char *argv[])
{
	int ret = 0;
	int i;
	struct v4l2_buffer buf;
	struct v4l2_requestbuffers reqbuf;
	enum v4l2_buf_type type;
	int last = 0;

	init_usage(argc, argv);
	init_fb();

	srand(time(NULL) ^ getpid());
	sleep(initial_delay);

	init_video_dev();

	memzero(reqbuf);
	reqbuf.count	= NUM_BUFS;
	reqbuf.type	= V4L2_BUF_TYPE_VIDEO_OUTPUT;
	type		= V4L2_BUF_TYPE_VIDEO_OUTPUT;
	reqbuf.memory	= V4L2_MEMORY_MMAP;
	ret = ioctl(vid_fd, VIDIOC_REQBUFS, &reqbuf);
	perror_exit(ret != 0, "ioctl");
	num_src_bufs = reqbuf.count;
	debug("Got %d src buffers\n", num_src_bufs);

	reqbuf.count	= NUM_BUFS;
	reqbuf.type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(vid_fd, VIDIOC_REQBUFS, &reqbuf);
	perror_exit(ret != 0, "ioctl");
	num_dst_bufs = reqbuf.count;
	debug("Got %d dst buffers\n", num_dst_bufs);

	for (i = 0; i < num_src_bufs; ++i) {
		buf.type	= V4L2_BUF_TYPE_VIDEO_OUTPUT;
		buf.memory	= V4L2_MEMORY_MMAP;
		buf.index	= i;

		ret = ioctl(vid_fd, VIDIOC_QUERYBUF, &buf);
		perror_exit(ret != 0, "ioctl");
		debug("QUERYBUF returned offset: %x\n", buf.m.offset);

		src_buf_size[i] = buf.length;
		p_src_buf[i] = mmap(NULL, buf.length,
				    PROT_READ | PROT_WRITE, MAP_SHARED,
				    vid_fd, buf.m.offset);
		perror_exit(MAP_FAILED == p_src_buf[i], "mmap");
	}

	for (i = 0; i < num_dst_bufs; ++i) {
		buf.type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory	= V4L2_MEMORY_MMAP;
		buf.index	= i;

		ret = ioctl(vid_fd, VIDIOC_QUERYBUF, &buf);
		perror_exit(ret != 0, "ioctl");
		debug("QUERYBUF returned offset: %x\n", buf.m.offset);

		dst_buf_size[i] = buf.length;
		p_dst_buf[i] = mmap(NULL, buf.length,
				    PROT_READ | PROT_WRITE, MAP_SHARED,
				    vid_fd, buf.m.offset);
		perror_exit(MAP_FAILED == p_dst_buf[i], "mmap");
	}

	for (i = 0; i < num_src_bufs; ++i) {

		gen_src_buf(p_src_buf[i], src_buf_size[i]);

		memzero(buf);
		buf.type	= V4L2_BUF_TYPE_VIDEO_OUTPUT;
		buf.memory	= V4L2_MEMORY_MMAP;
		buf.index	= i;

		ret = ioctl(vid_fd, VIDIOC_QBUF, &buf);
		perror_exit(ret != 0, "ioctl");
	}

	for (i = 0; i < num_dst_bufs; ++i) {
		memzero(buf);
		buf.type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory	= V4L2_MEMORY_MMAP;
		buf.index	= i;

		ret = ioctl(vid_fd, VIDIOC_QBUF, &buf);
		perror_exit(ret != 0, "ioctl");
	}

	type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
	ret = ioctl(vid_fd, VIDIOC_STREAMON, &type);
	debug("STREAMON OUTPUT (%d): %d\n", VIDIOC_STREAMON, ret);
	perror_exit(ret != 0, "ioctl");

	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(vid_fd, VIDIOC_STREAMON, &type);
	debug("STREAMON CAPTURE (%d): %d\n", VIDIOC_STREAMON, ret);
	perror_exit(ret != 0, "ioctl");

	while (num_frames) {
		fd_set read_fds;
		int r;

		FD_ZERO(&read_fds);
		FD_SET(vid_fd, &read_fds);

		debug("Before select\n");
		//r = select(vid_fd + 1, &read_fds, NULL, NULL, 0);
		//perror_exit(r < 0, "select");
		debug("After select\n");

		if (num_frames == 1)
			last = 1;
		if (read_frame(last)) {
			fprintf(stderr, "Read frame failed\n");
			break;
		}
		--num_frames;
		printf("FRAMES LEFT: %d\n", num_frames);
	}


done:
	close(vid_fd);
	close(fb_fd);

	for (i = 0; i < num_src_bufs; ++i)
		munmap(p_src_buf[i], src_buf_size[i]);

	for (i = 0; i < num_dst_bufs; ++i)
		munmap(p_dst_buf[i], dst_buf_size[i]);

	return ret;
}


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux