aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanimir Varbanov <stanimir.varbanov@linaro.org>2016-02-11 14:56:28 +0200
committerStanimir Varbanov <stanimir.varbanov@linaro.org>2016-06-13 18:34:35 +0300
commitfe5546222c5bb44693f2c167c6fc2281b1b34e1e (patch)
treea3d37ef58bc4acad9a6bf959bce3ed262804221a
parent8eb7956ed0dc230b2136163b7a5fad1a1a07cb18 (diff)
downloadv4l2-encode-fe5546222c5bb44693f2c167c6fc2281b1b34e1e.tar.gz
add test pattern generator instead of input file
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
-rw-r--r--Makefile2
-rw-r--r--args.c11
-rw-r--r--common.h35
-rw-r--r--gentest.c178
-rw-r--r--gentest.h9
-rw-r--r--main.c59
-rw-r--r--video.c14
7 files changed, 237 insertions, 71 deletions
diff --git a/Makefile b/Makefile
index c5d61b8..6bcfff7 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,7 @@ INCLUDES = -I$(KERNELHEADERS) -I/usr/include/drm
#-I$(TARGETROOT)/usr/include/linux
-SOURCES = main.c fileops.c args.c video.c
+SOURCES = main.c fileops.c args.c video.c gentest.c
OBJECTS := $(SOURCES:.c=.o)
EXEC = v4l2_encode
CFLAGS = -Wall -g -std=gnu99
diff --git a/args.c b/args.c
index 25bbf73..0dd0b58 100644
--- a/args.c
+++ b/args.c
@@ -36,7 +36,6 @@ void print_usage(char *name)
printf("\t-c <codec> - The codec to be used for encoding\n");
printf("\t\t Available codecs: mpeg4, h264\n");
printf("\t-d use dmabuf instead of mmap\n");
- printf("\t-i <file> - Input file name in NV12\n");
printf("\t-m <device> - video encoder device (e.g. /dev/video33)\n");
printf("\t-w video width\n");
printf("\t-h video height\n");
@@ -74,17 +73,15 @@ int parse_args(struct instance *i, int argc, char **argv)
init_to_defaults(i);
- while ((c = getopt(argc, argv, "w:h:c:di:m:f:n:")) != -1) {
+ while ((c = getopt(argc, argv, "w:h:c:d:m:f:n:")) != -1) {
switch (c) {
case 'c':
i->codec = get_codec(optarg);
+ i->codec_name = optarg;
break;
case 'd':
i->use_dmabuf = 1;
break;
- case 'i':
- i->in.name = optarg;
- break;
case 'm':
i->video.name = optarg;
break;
@@ -107,8 +104,8 @@ int parse_args(struct instance *i, int argc, char **argv)
}
}
- if (!i->in.name || !i->video.name) {
- err("The following arguments are required: -i -m -c");
+ if (!i->video.name) {
+ err("The following arguments are required: -m -c");
return -1;
}
diff --git a/common.h b/common.h
index b6dabba..804ac1d 100644
--- a/common.h
+++ b/common.h
@@ -64,6 +64,8 @@
#define memzero(x) memset(&(x), 0, sizeof (x));
+#define ALIGN(val, align) ((val + (align - 1)) & ~(align - 1))
+
/* Maximum number of output buffers */
#define MAX_OUT_BUF 16
@@ -110,34 +112,34 @@ struct video {
int fd;
/* Output queue related */
- int out_buf_cnt;
- int out_buf_size;
+ unsigned int out_buf_cnt;
+ unsigned int out_buf_size;
uint32_t out_buf_off[MAX_OUT_BUF];
uint8_t *out_buf_addr[MAX_OUT_BUF];
int out_buf_flag[MAX_OUT_BUF];
/* Capture queue related */
- int cap_w;
- int cap_h;
- int cap_crop_w;
- int cap_crop_h;
- int cap_crop_left;
- int cap_crop_top;
- int cap_buf_cnt;
- int cap_buf_cnt_min;
- int cap_buf_size[CAP_PLANES];
+ unsigned int cap_w;
+ unsigned int cap_h;
+ unsigned int cap_crop_w;
+ unsigned int cap_crop_h;
+ unsigned int cap_crop_left;
+ unsigned int cap_crop_top;
+ unsigned int cap_buf_cnt;
+ unsigned int cap_buf_cnt_min;
+ unsigned int cap_buf_size[CAP_PLANES];
uint32_t cap_buf_off[MAX_CAP_BUF][CAP_PLANES];
uint8_t *cap_buf_addr[MAX_CAP_BUF][CAP_PLANES];
- int cap_buf_flag[MAX_CAP_BUF];
- int cap_buf_queued;
+ unsigned int cap_buf_flag[MAX_CAP_BUF];
+ unsigned int cap_buf_queued;
unsigned long total_encoded;
};
struct instance {
- int width;
- int height;
- int save_encoded;
+ unsigned int width;
+ unsigned int height;
+ unsigned int save_encoded;
char *save_path;
unsigned long num_frames_to_save;
@@ -153,6 +155,7 @@ struct instance {
/* Codec to be used for encoding */
unsigned long codec;
+ char *codec_name;
pthread_mutex_t lock;
diff --git a/gentest.c b/gentest.c
new file mode 100644
index 0000000..03d9340
--- /dev/null
+++ b/gentest.c
@@ -0,0 +1,178 @@
+/*
+ * DRM based mode setting test program
+ * Copyright 2008 Tungsten Graphics
+ * Jakob Bornecrantz <jakob@tungstengraphics.com>
+ * Copyright 2008 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+
+enum yuv_order {
+ YUV_YCbCr = 1,
+ YUV_YCrCb = 2,
+ YUV_YC = 4,
+ YUV_CY = 8,
+};
+
+struct yuv_info {
+ enum yuv_order order;
+ unsigned int xsub;
+ unsigned int ysub;
+ unsigned int chroma_stride;
+};
+
+struct color_yuv {
+ unsigned char y;
+ unsigned char u;
+ unsigned char v;
+};
+
+#define MAKE_YUV_601_Y(r, g, b) \
+ ((( 66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16)
+#define MAKE_YUV_601_U(r, g, b) \
+ (((-38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128)
+#define MAKE_YUV_601_V(r, g, b) \
+ (((112 * (r) - 94 * (g) - 18 * (b) + 128) >> 8) + 128)
+
+static void fill_yuv_planar_noise(unsigned char *y_mem, unsigned char *u_mem,
+ unsigned char *v_mem, unsigned int width,
+ unsigned int height, unsigned int stride)
+{
+ const struct yuv_info yuv = { YUV_YCbCr, 2, 2, 2 }; /* NV12 */
+ unsigned int cs = yuv.chroma_stride;
+ unsigned int xsub = yuv.xsub;
+ unsigned int ysub = yuv.ysub;
+ unsigned int x;
+ unsigned int y;
+ struct color_yuv color;
+ unsigned int c;
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ c = rand() % 192;
+
+ if (c > 128)
+ color.y = 236;
+ else
+ color.y = 16;
+ color.u = 128;
+ color.v = 128;
+
+ y_mem[x] = color.y;
+ u_mem[x / xsub * cs] = color.u;
+ v_mem[x / xsub * cs] = color.v;
+ }
+
+ y_mem += stride;
+
+ if ((y + 1) % ysub == 0) {
+ u_mem += stride * cs / xsub;
+ v_mem += stride * cs / xsub;
+ }
+ }
+
+}
+
+static void fill_yuv_planar(unsigned char *y_mem, unsigned char *u_mem,
+ unsigned char *v_mem, unsigned int width,
+ unsigned int height, unsigned int stride)
+{
+ const struct yuv_info yuv = { YUV_YCbCr, 2, 2, 2 }; /* NV12 */
+ unsigned int cs = yuv.chroma_stride;
+ unsigned int xsub = yuv.xsub;
+ unsigned int ysub = yuv.ysub;
+ unsigned int x;
+ unsigned int y;
+ unsigned int r, g, b;
+ struct color_yuv color;
+
+ r = 0;
+ g = 0;
+ b = 192;
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ if (x % 128 == 0) {
+ r = r ? 0 : 192;
+ b = b ? 0 : 192;
+ }
+
+ color.y = MAKE_YUV_601_Y(r, g, b);
+ color.u = MAKE_YUV_601_U(r, g, b);
+ color.v = MAKE_YUV_601_V(r, g, b);
+
+ y_mem[x] = color.y;
+ u_mem[x / xsub * cs] = color.u;
+ v_mem[x / xsub * cs] = color.v;
+ }
+
+ y_mem += stride;
+
+ if ((y + 1) % ysub == 0) {
+ u_mem += stride * cs / xsub;
+ v_mem += stride * cs / xsub;
+ }
+ }
+}
+
+static void *testbuf;
+
+int gentest_init(unsigned int width, unsigned int height, unsigned int size)
+{
+ unsigned int stride = ALIGN(width, 128);
+ unsigned char *y_mem, *u_mem, *v_mem;
+
+ srand(1);
+
+ testbuf = malloc(size);
+ if (!testbuf)
+ return -1;
+
+ y_mem = testbuf;
+ u_mem = testbuf + stride * ALIGN(height, 32);
+ v_mem = u_mem + 1;
+
+ fill_yuv_planar(y_mem, u_mem, v_mem, width, height, stride);
+
+ return 0;
+}
+
+void gentest_deinit(void)
+{
+ if (testbuf)
+ free(testbuf);
+}
+
+void gentest_fill(unsigned int width, unsigned int height, unsigned char *to,
+ unsigned int size)
+{
+ unsigned int stride = ALIGN(width, 128);
+ unsigned char *y_mem = to;
+ unsigned char *u_mem = to + stride * ALIGN(height, 32);
+ unsigned char *v_mem = u_mem + 1;
+
+ memcpy(to, testbuf, size);
+ fill_yuv_planar_noise(y_mem, u_mem, v_mem, width/4, height/4, stride);
+}
diff --git a/gentest.h b/gentest.h
new file mode 100644
index 0000000..64d8fb7
--- /dev/null
+++ b/gentest.h
@@ -0,0 +1,9 @@
+#ifndef INCLUDE_GENTEST_H
+#define INCLUDE_GENTEST_H
+
+int gentest_init(unsigned int width, unsigned int height, unsigned int size);
+void gentest_deinit(void);
+void gentest_fill(unsigned int width, unsigned int height, unsigned char *to,
+ unsigned int size);
+
+#endif /* INCLUDE_GENTEST_H */ \ No newline at end of file
diff --git a/main.c b/main.c
index c6f4458..d562338 100644
--- a/main.c
+++ b/main.c
@@ -34,11 +34,13 @@
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
+#include <stdlib.h>
#include "args.h"
#include "common.h"
#include "fileops.h"
#include "video.h"
+#include "gentest.h"
/* This is the size of the buffer for the compressed stream.
* It limits the maximum compressed frame size. */
@@ -119,14 +121,15 @@ int save_encoded(struct instance *i, const void *buf, unsigned int size)
int ret;
struct output *out = &i->out;
ssize_t written;
+ const char *ext = i->codec_name;
if (!i->save_encoded)
return 0;
if (!i->save_path)
- ret = sprintf(filename, "/mnt/sdcard/encoded.h264");
+ ret = sprintf(filename, "/mnt/sdcard/encoded.%s", ext);
else
- ret = sprintf(filename, "%s/encoded.h264", i->save_path);
+ ret = sprintf(filename, "%s/encoded.%s", i->save_path, ext);
if (ret < 0) {
err("sprintf fail (%s)", strerror(errno));
return -1;
@@ -158,39 +161,15 @@ write:
}
static int input_read(struct instance *inst, unsigned int index,
- unsigned int *used, unsigned int *fs)
+ unsigned int *used, unsigned int *fs)
{
struct video *vid = &inst->video;
- uint8_t *to = vid->out_buf_addr[index];
- int ret;
- char filename[64];
- static int num = 1;
+ unsigned char *to = vid->out_buf_addr[index];
*used = vid->out_buf_size;
*fs = vid->out_buf_size;
- ret = sprintf(filename, "/mnt/sdcard/frame%04d.nv12", num++);
- if (ret < 0) {
- err("sprintf fail (%s)", strerror(errno));
- return -1;
- }
-
- dbg("open %s", filename);
-
- ret = input_open(inst, filename);
- if (ret)
- return ret;
-
- dbg("input nv12 size:%d, sizeimage:%d", inst->in.size, *fs);
-
- memcpy(to, inst->in.p, inst->in.size);
-
- input_close(inst);
-
- usleep(33 * 1000);
-
- if (num > 14)
- num = 1;
+ gentest_fill(inst->width, inst->height, to, vid->out_buf_size);
return 0;
}
@@ -291,7 +270,7 @@ void *main_thread_func(void *args)
vid->total_encoded++;
- save_encoded(i, (void *)vid->cap_buf_addr[n][0],
+ save_encoded(i, (const void *)vid->cap_buf_addr[n][0],
bytesused);
ret = video_queue_buf_cap(i, n);
@@ -345,19 +324,13 @@ int main(int argc, char **argv)
vid->total_encoded = 0;
-// ret = input_open(&inst, inst.in.name);
-// if (ret)
-// goto err;
-
ret = video_open(&inst, inst.video.name);
if (ret)
goto err;
-#if 1
- /* TODO: */
+
ret = subscribe_for_events(vid->fd);
if (ret)
goto err;
-#endif
if (inst.use_dmabuf)
ret = video_setup_capture_dmabuf(&inst, 2, inst.width,
@@ -371,11 +344,14 @@ int main(int argc, char **argv)
if (ret)
goto err;
+ ret = gentest_init(inst.width, inst.height, vid->out_buf_size);
+ if (ret)
+ goto err;
+
ret = video_set_control(&inst);
if (ret)
goto err;
- /* queue all capture buffers */
for (n = 0; n < vid->cap_buf_cnt; n++) {
ret = video_queue_buf_cap(&inst, n);
if (ret)
@@ -422,13 +398,14 @@ int main(int argc, char **argv)
info("Total frames encoded %ld", vid->total_encoded);
- cleanup(&inst);
-
pthread_mutex_destroy(&inst.lock);
+ cleanup(&inst);
+ gentest_deinit();
return 0;
err:
+ pthread_mutex_destroy(&inst.lock);
cleanup(&inst);
+ gentest_deinit();
return 1;
}
-
diff --git a/video.c b/video.c
index b704fa2..309bff2 100644
--- a/video.c
+++ b/video.c
@@ -560,21 +560,23 @@ int video_setup_output(struct instance *i, unsigned long codec,
return -1;
}
- info("Setup OUTPUT buffer size=%u (requested=%u)",
- fmt.fmt.pix_mp.plane_fmt[0].sizeimage, size);
+ info("Setup OUTPUT buffer size=%u (requested=%u), bytesperline:%u",
+ fmt.fmt.pix_mp.plane_fmt[0].sizeimage, size,
+ fmt.fmt.pix_mp.plane_fmt[0].bytesperline);
vid->out_buf_size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
memzero(g_fmt);
- g_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ g_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
g_fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
ret = ioctl(vid->fd, VIDIOC_G_FMT, &g_fmt);
if (ret) {
err("Failed to get format on OUTPUT (%s)", strerror(errno));
} else {
- info("Get format sizeimage is %d",
- g_fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
+ info("Get format sizeimage:%u, bytesperline:%u",
+ g_fmt.fmt.pix_mp.plane_fmt[0].sizeimage,
+ g_fmt.fmt.pix_mp.plane_fmt[0].bytesperline);
}
memzero(reqbuf);
@@ -624,7 +626,7 @@ int video_setup_output(struct instance *i, unsigned long codec,
vid->out_buf_flag[n] = 0;
}
- dbg("Succesfully mmapped %d OUTPUT buffers", n);
+ info("querybuf: OUTPUT sizeimage %d", vid->out_buf_size);
return 0;
}