aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile57
-rw-r--r--args.c136
-rw-r--r--args.h33
-rw-r--r--common.h174
-rw-r--r--fileops.c60
-rw-r--r--fileops.h34
-rw-r--r--main.c520
-rw-r--r--msm-v4l2-controls.h455
-rw-r--r--video.c619
-rw-r--r--video.h73
10 files changed, 2161 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..555035f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,57 @@
+# V4L2 Codec decoding example application
+# Kamil Debski <k.debski@samsung.com>
+#
+# Copyright 2012 Samsung Electronics Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Toolchain path
+#TCPATH = arm-linux-gnueabihf-
+TCPATH = aarch64-linux-gnu-
+KERNELHEADERS = /usr/include
+
+CC = ${TCPATH}gcc
+AR = "${TCPATH}ar rc"
+AR2 = ${TCPATH}ranlib make -j4
+
+
+INCLUDES = -I$(KERNELHEADERS) -I/usr/include/drm
+
+#INCLUDES = -I$(KERNELHEADERS)/include
+
+#-I$(TARGETROOT)/usr/include/linux
+
+SOURCES = main.c fileops.c args.c video.c
+OBJECTS := $(SOURCES:.c=.o)
+EXEC = v4l2_decode
+CFLAGS = -Wall -g -std=gnu99
+#-Os
+LIBS = -lpthread -ldrm_freedreno -lm
+LIBPATH = -L/usr/lib/aarch64-linux-gnu
+LDFLAGS = -o $(EXEC) $(LIBPATH) $(LIBS)
+
+all: $(EXEC)
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCLUDES) $<
+
+$(EXEC): $(OBJECTS)
+ $(CC) -o v4l2_decode $(OBJECTS) -lpthread -ldrm -ldrm_freedreno
+
+clean:
+ rm -f *.o $(EXEC)
+
+install:
+
+.PHONY: clean all
diff --git a/args.c b/args.c
new file mode 100644
index 0000000..689e705
--- /dev/null
+++ b/args.c
@@ -0,0 +1,136 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ * Argument parser
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 Linaro Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/videodev2.h>
+
+#include "common.h"
+#include "parser.h"
+
+
+void print_usage(char *name)
+{
+ printf("Usage:\n");
+ printf("\t%s\n", name);
+ printf("\t-c <codec> - The codec of the encoded stream\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\n");
+ printf("\t-m <device> - video decoder device (e.g. /dev/video8)\n");
+ printf("\t-w video width\n");
+ printf("\t-h video height\n");
+ printf("\t-f save frames on disk\n");
+
+ printf("\n");
+}
+
+void init_to_defaults(struct instance *i)
+{
+ memset(i, 0, sizeof(*i));
+}
+
+int get_codec(char *str)
+{
+ if (strncasecmp("mpeg4", str, 5) == 0) {
+ return V4L2_PIX_FMT_MPEG4;
+ } else if (strncasecmp("h264", str, 5) == 0) {
+ return V4L2_PIX_FMT_H264;
+ } else if (strncasecmp("h263", str, 5) == 0) {
+ return V4L2_PIX_FMT_H263;
+ } else if (strncasecmp("xvid", str, 5) == 0) {
+ return V4L2_PIX_FMT_XVID;
+ } else if (strncasecmp("mpeg2", str, 5) == 0) {
+ return V4L2_PIX_FMT_MPEG2;
+ } else if (strncasecmp("mpeg1", str, 5) == 0) {
+ return V4L2_PIX_FMT_MPEG1;
+ }
+ return 0;
+}
+
+int parse_args(struct instance *i, int argc, char **argv)
+{
+ int c;
+
+ init_to_defaults(i);
+
+ while ((c = getopt(argc, argv, "w:h:c:di:m:f:")) != -1) {
+ switch (c) {
+ case 'c':
+ i->parser.codec = get_codec(optarg);
+ break;
+ case 'd':
+ i->use_dmabuf = 1;
+ break;
+ case 'i':
+ i->in.name = optarg;
+ break;
+ case 'm':
+ i->video.name = optarg;
+ break;
+ case 'w':
+ i->width = atoi(optarg);
+ break;
+ case 'h':
+ i->height = atoi(optarg);
+ break;
+ case 'f':
+ i->save_frames = 1;
+ i->save_path = optarg;
+ break;
+ default:
+ err("Bad argument");
+ return -1;
+ }
+ }
+
+ if (!i->in.name || !i->video.name) {
+ err("The following arguments are required: -i -m -c");
+ return -1;
+ }
+
+ if (!i->parser.codec) {
+ err("Unknown or not set codec (-c)");
+ return -1;
+ }
+
+ switch (i->parser.codec) {
+ case V4L2_PIX_FMT_XVID:
+ case V4L2_PIX_FMT_H263:
+ case V4L2_PIX_FMT_MPEG4:
+ i->parser.func = parse_mpeg4_stream;
+ break;
+ case V4L2_PIX_FMT_H264:
+ i->parser.func = parse_h264_stream;
+ break;
+ case V4L2_PIX_FMT_MPEG1:
+ case V4L2_PIX_FMT_MPEG2:
+ i->parser.func = parse_mpeg2_stream;
+ break;
+ }
+
+ return 0;
+}
+
diff --git a/args.h b/args.h
new file mode 100644
index 0000000..93468e5
--- /dev/null
+++ b/args.h
@@ -0,0 +1,33 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ * Argument parser header file
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef INCLUDE_ARGS_H
+#define INCLUDE_ARGS_H
+
+#include "common.h"
+
+/* Pritn usage information of the application */
+void print_usage(char *name);
+/* Parse the arguments that have been given to the application */
+int parse_args(struct instance *i, int argc, char **argv);
+
+#endif /* INCLUDE_FILEOPS_H */
+
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..9265035
--- /dev/null
+++ b/common.h
@@ -0,0 +1,174 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ * Common stuff header file
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 Linaro Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef INCLUDE_COMMON_H
+#define INCLUDE_COMMON_H
+
+#include <stdio.h>
+#include <semaphore.h>
+
+#include "parser.h"
+#include "queue.h"
+#include "drm-funcs.h"
+
+/* When ADD_DETAILS is defined every debug and error message contains
+ * information about the file, function and line of code where it has
+ * been called */
+#define ADD_DETAILS
+
+/* When DEBUG is defined debug messages are printed on the screen.
+ * Otherwise only error messages are displayed. */
+//#define DEBUG
+
+#ifdef ADD_DETAILS
+#define err(msg, ...) \
+ fprintf(stderr, "Error (%s:%s:%d): " msg "\n", __FILE__, \
+ __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define err(msg, ...) \
+ fprintf(stderr, "Error: " msg "\n", __FILE__, ##__VA_ARGS__)
+#endif /* ADD_DETAILS */
+
+#define info(msg, ...) \
+ fprintf(stderr, "Info : " msg "\n", ##__VA_ARGS__)
+
+#ifdef DEBUG
+#ifdef ADD_DETAILS
+#define dbg(msg, ...) \
+ fprintf(stdout, "(%s:%s:%d): " msg "\n", __FILE__, \
+ __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define dbg(msg, ...) \
+ fprintf(stdout, msg "\n", ##__VA_ARGS__)
+#endif /* ADD_DETAILS */
+#else /* DEBUG */
+#define dbg(...) {}
+#endif /* DEBUG */
+
+#define memzero(x) memset(&(x), 0, sizeof (x));
+
+/* Maximum number of output buffers */
+#define MAX_OUT_BUF 16
+
+/* Maximum number of capture buffers (32 is the limit imposed by MFC */
+#define MAX_CAP_BUF 32
+
+/* Number of output planes */
+#define OUT_PLANES 1
+
+/* Number of capture planes */
+#define CAP_PLANES 1
+
+/* Maximum number of planes used in the application */
+#define MAX_PLANES CAP_PLANES
+
+/* Maximum number of frame buffers - used for double buffering and
+ * vsyns synchronisation */
+#define FB_MAX_BUFS 2
+
+/* The buffer is free to use by video decoder */
+#define BUF_FREE 0
+
+/* Input file related parameters */
+struct input {
+ char *name;
+ int fd;
+ char *p;
+ int size;
+ int offs;
+};
+
+/* video decoder related parameters */
+struct video {
+ char *name;
+ int fd;
+
+ /* Output queue related */
+ int out_buf_cnt;
+ int out_buf_size;
+ int out_buf_off[MAX_OUT_BUF];
+ char *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];
+ int cap_buf_off[MAX_CAP_BUF][CAP_PLANES];
+ char *cap_buf_addr[MAX_CAP_BUF][CAP_PLANES];
+ int cap_buf_flag[MAX_CAP_BUF];
+ int cap_buf_queued;
+
+ unsigned long total_captured;
+};
+
+/* Parser related parameters */
+struct parser {
+ struct mfc_parser_context ctx;
+ unsigned long codec;
+ /* Callback function to the real parsing function.
+ * Dependent on the codec used. */
+ int (*func)(struct mfc_parser_context *ctx,
+ char* in, int in_size, char* out, int out_size,
+ int *consumed, int *frame_size, char get_head);
+ /* Set when the parser has finished and end of file has
+ * been reached */
+ int finished;
+};
+
+struct instance {
+ int width;
+ int height;
+ int save_frames;
+ char *save_path;
+
+ int use_dmabuf;
+
+ /* Input file related parameters */
+ struct input in;
+
+ /* video decoder related parameters */
+ struct video video;
+
+ /* Parser related parameters */
+ struct parser parser;
+
+ pthread_mutex_t lock;
+ struct queue queue;
+
+ /* Control */
+ int error; /* The error flag */
+ int finish; /* Flag set when decoding has been completed and all
+ threads finish */
+
+ struct drm_buffer disp_buf[MAX_CAP_BUF];
+};
+
+#endif /* INCLUDE_COMMON_H */
+
diff --git a/fileops.c b/fileops.c
new file mode 100644
index 0000000..17fbe47
--- /dev/null
+++ b/fileops.c
@@ -0,0 +1,60 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ * File operations
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "fileops.h"
+
+int input_open(struct instance *i, char *name)
+{
+ struct stat in_stat;
+
+ i->in.fd = open(name, O_RDONLY);
+ if (!i->in.fd) {
+ err("Failed to open file: %s", i->in.name);
+ return -1;
+ }
+
+ fstat(i->in.fd, &in_stat);
+
+ i->in.size = in_stat.st_size;
+ i->in.offs = 0;
+ i->in.p = mmap(0, i->in.size, PROT_READ, MAP_SHARED, i->in.fd, 0);
+ if (i->in.p == MAP_FAILED) {
+ err("Failed to map input file");
+ return -1;
+ }
+
+ return 0;
+}
+
+void input_close(struct instance *i)
+{
+ munmap(i->in.p, i->in.size);
+ close(i->in.fd);
+}
+
diff --git a/fileops.h b/fileops.h
new file mode 100644
index 0000000..5e1bb7c
--- /dev/null
+++ b/fileops.h
@@ -0,0 +1,34 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ * File operations header file
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef INCLUDE_FILEOPS_H
+#define INCLUDE_FILEOPS_H
+
+#include "common.h"
+
+/* Open and mmap the input file */
+int input_open(struct instance *i, char *name);
+/* Unmap and close the input file */
+void input_close(struct instance *i);
+
+#endif /* INCLUDE_FILEOPS_H */
+
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..5557276
--- /dev/null
+++ b/main.c
@@ -0,0 +1,520 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ * Main file of the application
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 Linaro Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <linux/videodev2.h>
+#include "msm-v4l2-controls.h"
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <poll.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "args.h"
+#include "common.h"
+#include "fileops.h"
+#include "video.h"
+
+/* This is the size of the buffer for the compressed stream.
+ * It limits the maximum compressed frame size. */
+#define STREAM_BUUFER_SIZE (1024 * 1024)
+
+/* The number of compress4ed stream buffers */
+#define STREAM_BUFFER_CNT 2
+
+/* The number of extra buffers for the decoded output.
+ * This is the number of buffers that the application can keep
+ * used and still enable video device to decode with the hardware. */
+#define RESULT_EXTRA_BUFFER_CNT 2
+
+static const int event_type[] = {
+ V4L2_EVENT_EOS,
+ V4L2_EVENT_SOURCE_CHANGE,
+};
+
+static struct timeval start, end;
+
+static void time_start(void)
+{
+ gettimeofday(&start, NULL);
+}
+
+static void print_time_delta(const char *prefix)
+{
+ unsigned long delta;
+
+ gettimeofday(&end, NULL);
+
+ delta = (end.tv_sec * 1000000 + end.tv_usec) -
+ (start.tv_sec * 1000000 + start.tv_usec);
+
+ delta = delta;
+
+ dbg("%s: %ld\n", prefix, delta);
+}
+
+static int subscribe_for_events(int fd)
+{
+ int size_event = sizeof(event_type) / sizeof(event_type[0]);
+ struct v4l2_event_subscription sub;
+ int i, ret;
+
+ for (i = 0; i < size_event; i++) {
+ memset(&sub, 0, sizeof(sub));
+ sub.type = event_type[i];
+ ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
+ if (ret < 0)
+ err("cannot subscribe for event type %d (%s)",
+ sub.type, strerror(errno));
+ }
+
+ return 0;
+}
+
+static int handle_v4l_events(struct video *vid)
+{
+ struct v4l2_event event;
+ int ret;
+
+ memset(&event, 0, sizeof(event));
+ ret = ioctl(vid->fd, VIDIOC_DQEVENT, &event);
+ if (ret < 0) {
+ err("vidioc_dqevent failed (%s) %d", strerror(errno), -errno);
+ return -errno;
+ }
+
+ switch (event.type) {
+ case V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT:
+ dbg("Port Reconfig recieved insufficient\n");
+ break;
+ case V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT:
+ dbg("Setting changed sufficient\n");
+ break;
+ case V4L2_EVENT_MSM_VIDC_FLUSH_DONE:
+ dbg("Flush Done Recieved \n");
+ break;
+ case V4L2_EVENT_MSM_VIDC_CLOSE_DONE:
+ dbg("Close Done Recieved \n");
+ break;
+ case V4L2_EVENT_MSM_VIDC_SYS_ERROR:
+ dbg("SYS Error Recieved \n");
+ break;
+ default:
+ dbg("unknown event type occurred %x\n", event.type);
+ break;
+ }
+
+ return 0;
+}
+
+void cleanup(struct instance *i)
+{
+ if (i->video.fd)
+ video_close(i);
+ if (i->in.fd)
+ input_close(i);
+}
+
+int extract_and_process_header(struct instance *i)
+{
+ int used, fs;
+ int ret;
+ int n;
+ struct video *vid = &i->video;
+
+ ret = i->parser.func(&i->parser.ctx,
+ i->in.p + i->in.offs,
+ i->in.size - i->in.offs,
+ i->video.out_buf_addr[0],
+ i->video.out_buf_size,
+ &used, &fs, 1);
+
+ if (ret == 0) {
+ err("Failed to extract header from stream");
+ return -1;
+ }
+
+ /* For H263 the header is passed with the first frame, so we should
+ * pass it again */
+ if (i->parser.codec != V4L2_PIX_FMT_H263)
+ i->in.offs += used;
+ else
+ /* To do this we shall reset the stream parser to the initial
+ * configuration */
+ parse_stream_init(&i->parser.ctx);
+
+ dbg("Extracted header of size %d", fs);
+
+ ret = video_queue_buf_out(i, 0, fs);
+ if (ret)
+ return -1;
+
+ dbg("queued output buffer %d", 0);
+
+ i->video.out_buf_flag[0] = 1;
+#if 1
+ for (n = 1; n < vid->out_buf_cnt; n++) {
+ ret = video_queue_buf_out(i, n, 1);
+ if (ret)
+ return -1;
+
+ i->video.out_buf_flag[n] = 1;
+ }
+#endif
+ ret = video_stream(i, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ VIDIOC_STREAMON);
+ if (ret)
+ return -1;
+
+ return 0;
+}
+
+int save_frame(struct instance *i, const void *buf, unsigned int size)
+{
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ char filename[64];
+ int fd;
+ int ret;
+ static unsigned int frame_num = 0;
+
+ if (!i->save_frames)
+ return 0;
+
+ if (!i->save_path)
+ ret = sprintf(filename, "/mnt/frame%04d.nv12", frame_num);
+ else
+ ret = sprintf(filename, "%s/frame%04d.nv12", i->save_path,
+ frame_num);
+ if (ret < 0) {
+ err("sprintf fail (%s)", strerror(errno));
+ return -1;
+ }
+
+ dbg("create file %s", filename);
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, mode);
+ if (fd < 0) {
+ err("cannot open file (%s)", strerror(errno));
+ return -1;
+ }
+
+ ret = write(fd, buf, size);
+ if (ret < 0) {
+ err("cannot write to file (%s)", strerror(errno));
+ return -1;
+ }
+
+ close(fd);
+
+ frame_num++;
+
+ return 0;
+}
+
+/* This threads is responsible for parsing the stream and
+ * feeding video decoder with consecutive frames to decode */
+void *parser_thread_func(void *args)
+{
+ struct instance *i = (struct instance *)args;
+ struct video *vid = &i->video;
+ int used, fs, n;
+ int ret;
+
+ dbg("Parser thread started");
+
+ while (!i->error && !i->finish && !i->parser.finished) {
+ n = 0;
+ pthread_mutex_lock(&i->lock);
+ while (n < vid->out_buf_cnt && vid->out_buf_flag[n])
+ n++;
+ pthread_mutex_unlock(&i->lock);
+
+ if (n < vid->out_buf_cnt && !i->parser.finished) {
+
+ ret = i->parser.func(&i->parser.ctx,
+ i->in.p + i->in.offs,
+ i->in.size - i->in.offs,
+ vid->out_buf_addr[n],
+ vid->out_buf_size,
+ &used, &fs, 0);
+
+ if (ret == 0 && i->in.offs == i->in.size) {
+ info("Parser has extracted all frames");
+ i->parser.finished = 1;
+ fs = 0;
+ }
+
+ dbg("Extracted frame of size %d", fs);
+
+ ret = video_queue_buf_out(i, n, fs);
+
+ pthread_mutex_lock(&i->lock);
+ vid->out_buf_flag[n] = 1;
+ pthread_mutex_unlock(&i->lock);
+
+ dbg("queued output buffer %d", n);
+
+ i->in.offs += used;
+ }
+ }
+
+ dbg("Parser thread finished");
+
+ return NULL;
+}
+
+void *main_thread_func(void *args)
+{
+ struct instance *i = (struct instance *)args;
+ struct video *vid = &i->video;
+ struct pollfd pfd;
+ short revents;
+ int ret, n, finished, disp_idx;
+
+ dbg("main thread started");
+
+ pfd.fd = vid->fd;
+ pfd.events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM |
+ POLLRDBAND | POLLPRI;
+
+ while (1) {
+ ret = poll(&pfd, 1, 10000);
+ if (!ret) {
+ err("poll timeout");
+ break;
+ } else if (ret < 0) {
+ err("poll error");
+ break;
+ }
+
+ revents = pfd.revents;
+
+ if (revents & (POLLIN | POLLRDNORM)) {
+ unsigned int bytesused;
+
+ /* capture buffer is ready */
+
+ dbg("dequeuing capture buffer");
+
+ if (i->use_dmabuf)
+ ret = video_dequeue_capture_dmabuf(
+ i, &n, &finished, &bytesused);
+ else
+ ret = video_dequeue_capture(i, &n, &finished,
+ &bytesused);
+ if (ret < 0)
+ goto next_event;
+
+ vid->cap_buf_flag[n] = 0;
+
+ dbg("decoded frame %ld", vid->total_captured);
+
+ if (finished)
+ break;
+
+ vid->total_captured++;
+
+ disp_idx = i->use_dmabuf ? n : 0;
+
+ time_start();
+
+ drm_display_buf(vid->cap_buf_addr[n][0],
+ &i->disp_buf[disp_idx], bytesused,
+ i->width, i->height);
+
+ print_time_delta("disp");
+
+ save_frame(i, (void *)vid->cap_buf_addr[n][0],
+ bytesused);
+
+ if (i->use_dmabuf)
+ ret = video_queue_buf_cap_dmabuf(
+ i, n, &i->disp_buf[n]);
+ else
+ ret = video_queue_buf_cap(i, n);
+
+ if (!ret)
+ vid->cap_buf_flag[n] = 1;
+ }
+
+next_event:
+ if (revents & (POLLOUT | POLLWRNORM)) {
+
+ dbg("dequeuing output buffer");
+
+ ret = video_dequeue_output(i, &n);
+ if (ret < 0) {
+ err("dequeue output buffer fail");
+ } else {
+ pthread_mutex_lock(&i->lock);
+ vid->out_buf_flag[n] = 0;
+ pthread_mutex_unlock(&i->lock);
+ }
+
+ dbg("dequeued output buffer %d", n);
+ }
+
+ if (revents & POLLPRI) {
+ dbg("v4l2 event");
+ handle_v4l_events(vid);
+ }
+ }
+
+ dbg("main thread finished");
+
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ struct instance inst;
+ struct video *vid = &inst.video;
+ pthread_t parser_thread;
+ pthread_t main_thread;
+ int ret, n;
+
+ ret = parse_args(&inst, argc, argv);
+ if (ret) {
+ print_usage(argv[0]);
+ return 1;
+ }
+
+ info("decoding resolution is %dx%d", inst.width, inst.height);
+
+ pthread_mutex_init(&inst.lock, 0);
+
+ vid->total_captured = 0;
+
+ ret = drm_init();
+ if (ret)
+ goto err;
+
+ ret = parse_stream_init(&inst.parser.ctx);
+ if (ret)
+ goto err;
+
+ 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
+ ret = video_setup_output(&inst, inst.parser.codec,
+ STREAM_BUUFER_SIZE, 1);
+ if (ret)
+ goto err;
+
+ ret = video_set_control(&inst);
+ if (ret)
+ goto err;
+
+ if (inst.use_dmabuf)
+ ret = video_setup_capture_dmabuf(&inst, 2, inst.width,
+ inst.height);
+ else
+ ret = video_setup_capture(&inst, 2, inst.width, inst.height);
+ if (ret)
+ goto err;
+
+ if (inst.use_dmabuf)
+ ret = drm_create_bufs(&inst.disp_buf[0], vid->cap_buf_cnt,
+ inst.width, inst.height, 0);
+ else
+ ret = drm_create_bufs(&inst.disp_buf[0], 1, inst.width,
+ inst.height, 1);
+ if (ret)
+ goto err;
+
+ ret = extract_and_process_header(&inst);
+ if (ret)
+ goto err;
+
+#if 0
+ for (n = 0; n < vid->cap_buf_cnt; n++)
+ video_export_buf(&inst, n);
+#endif
+
+ /* queue all capture buffers */
+ for (n = 0; n < vid->cap_buf_cnt; n++) {
+ if (inst.use_dmabuf)
+ ret = video_queue_buf_cap_dmabuf(&inst, n,
+ &inst.disp_buf[n]);
+ else
+ ret = video_queue_buf_cap(&inst, n);
+
+ if (ret)
+ goto err;
+
+ vid->cap_buf_flag[n] = 1;
+ }
+
+ ret = video_stream(&inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ VIDIOC_STREAMON);
+ if (ret)
+ goto err;
+
+ dbg("Launching threads");
+
+ if (pthread_create(&parser_thread, NULL, parser_thread_func, &inst))
+ goto err;
+
+ if (pthread_create(&main_thread, NULL, main_thread_func, &inst))
+ goto err;
+
+ pthread_join(parser_thread, 0);
+ pthread_join(main_thread, 0);
+
+ dbg("Threads have finished");
+
+ video_stop(&inst);
+
+ info("Total frames captured %ld", vid->total_captured);
+
+ if (inst.use_dmabuf)
+ drm_destroy_bufs(inst.disp_buf, vid->cap_buf_cnt, 0);
+ else
+ drm_destroy_bufs(inst.disp_buf, 1, 1);
+
+ drm_deinit();
+
+ cleanup(&inst);
+
+ pthread_mutex_destroy(&inst.lock);
+
+ return 0;
+err:
+ cleanup(&inst);
+ return 1;
+}
+
diff --git a/msm-v4l2-controls.h b/msm-v4l2-controls.h
new file mode 100644
index 0000000..0b5639f
--- /dev/null
+++ b/msm-v4l2-controls.h
@@ -0,0 +1,455 @@
+#ifndef __MSM_V4L2_CONTROLS_H__
+#define __MSM_V4L2_CONTROLS_H__
+
+#include <linux/v4l2-controls.h>
+
+/* MPEG-class control IDs specific to the msm_vidc driver */
+#define V4L2_CID_MPEG_MSM_VIDC_BASE (V4L2_CTRL_CLASS_MPEG | 0x2000)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+0)
+#define V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+1)
+#define V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+2)
+#define V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+3)
+enum v4l2_mpeg_vidc_video_divx_format_type {
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4 = 0,
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5 = 1,
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6 = 2,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+4)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+5)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT (V4L2_CID_MPEG_MSM_VIDC_BASE+6)
+enum v4l2_mpeg_vidc_video_stream_format {
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES = 0,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER = 1,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH = 2,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH = 3,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH = 4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER (V4L2_CID_MPEG_MSM_VIDC_BASE+7)
+enum v4l2_mpeg_vidc_video_output_order {
+ V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY = 0,
+ V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE (V4L2_CID_MPEG_MSM_VIDC_BASE+8)
+#define V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD (V4L2_CID_MPEG_MSM_VIDC_BASE+9)
+#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+10)
+#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+11)
+#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME (V4L2_CID_MPEG_MSM_VIDC_BASE+12)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL (V4L2_CID_MPEG_MSM_VIDC_BASE+13)
+enum v4l2_mpeg_vidc_video_rate_control {
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR = 3,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR = 4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ROTATION (V4L2_CID_MPEG_MSM_VIDC_BASE+14)
+enum v4l2_mpeg_vidc_video_rotation {
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180 = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270 = 3,
+};
+#define MSM_VIDC_BASE V4L2_CID_MPEG_MSM_VIDC_BASE
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL (MSM_VIDC_BASE+15)
+enum v4l2_mpeg_vidc_h264_cabac_model {
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0 = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1 = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2 = 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE (MSM_VIDC_BASE+16)
+enum v4l2_mpeg_vidc_video_intra_refresh_mode {
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE = 3,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM = 4,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+17)
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE+18)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+19)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE (V4L2_CID_MPEG_MSM_VIDC_BASE+20)
+enum v4l2_mpeg_vidc_video_h263_profile {
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE = 0,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING = 1,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE = 2,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2 = 3,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3 = 4,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION = 5,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET = 6,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE = 7,
+ V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY = 8,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+21)
+enum v4l2_mpeg_vidc_video_h263_level {
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0 = 0,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0 = 1,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0 = 2,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0 = 3,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5 = 4,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0 = 5,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0 = 6,
+ V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 22)
+enum v4l2_mpeg_vidc_video_h264_au_delimiter {
+ V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED = 1
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
+enum v4l2_mpeg_vidc_video_sync_frame_decode {
+ V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE = 0,
+ V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE = 1
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE (V4L2_CID_MPEG_MSM_VIDC_BASE+24)
+#define V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 25)
+enum v4l2_mpeg_vidc_extradata {
+ V4L2_MPEG_VIDC_EXTRADATA_NONE = 0,
+ V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION = 1,
+ V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO = 2,
+ V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP = 3,
+ V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP = 4,
+ V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP = 5,
+ V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING = 6,
+ V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE = 7,
+ V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW = 8,
+ V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI = 9,
+ V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO = 10,
+ V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB = 11,
+ V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER = 12,
+ V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP = 13,
+ V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM = 14,
+ V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO = 15,
+ V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP = 16,
+ V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA = 17,
+ V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP = 18,
+ V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO = 19,
+ V4L2_MPEG_VIDC_EXTRADATA_LTR = 20,
+ V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI = 21,
+};
+
+#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26)
+enum v4l2_mpeg_vidc_perf_level {
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL = 0,
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE = 1,
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 27)
+
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 28)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 29)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 30)
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 31)
+enum v4l2_mpeg_vidc_video_alloc_mode_type {
+ V4L2_MPEG_VIDC_VIDEO_STATIC = 0,
+ V4L2_MPEG_VIDC_VIDEO_RING = 1,
+ V4L2_MPEG_VIDC_VIDEO_DYNAMIC = 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 32)
+enum v4l2_mpeg_vidc_video_assembly {
+ V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0,
+ V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 33)
+enum v4l2_mpeg_vidc_video_vp8_profile_level {
+ V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 34)
+enum v4l2_mpeg_vidc_video_h264_vui_bitstream_restrict {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 35)
+enum v4l2_mpeg_vidc_video_preserve_text_quality {
+ V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
+enum v4l2_mpeg_vidc_video_deinterlace {
+ V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 38)
+enum v4l2_mpeg_vidc_video_decoder_multi_stream {
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 39)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+40)
+enum v4l2_mpeg_vidc_video_mpeg2_level {
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0 = 0,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1 = 1,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2 = 2,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3 = 3,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE (V4L2_CID_MPEG_MSM_VIDC_BASE+41)
+enum v4l2_mpeg_vidc_video_mpeg2_profile {
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE = 0,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN = 1,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_422 = 2,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SNR_SCALABLE = 3,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SPATIAL_SCALABLE = 4,
+ V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH = 5,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 42)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 43)
+enum v4l2_mpeg_vidc_video_mvc_layout {
+ V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL = 0,
+ V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 44)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 45)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 46)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 47)
+
+enum v4l2_mpeg_vidc_video_ltrmode {
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE = 0,
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_MANUAL = 1,
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_PERIODIC = 2
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 48)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 49)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 50)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 51)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 52)
+enum v4l2_mpeg_vidc_video_rate_control_timestamp_mode {
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR = 0,
+ V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 53)
+enum vl42_mpeg_vidc_video_enable_initial_qp {
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME = 0x1,
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME = 0x2,
+ V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME = 0x4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 54)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 55)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 56)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 57)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 58)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 59)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 60)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 61)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 62)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 63)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 64)
+
+enum vl42_mpeg_vidc_video_vpx_error_resilience {
+ V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_ENABLED = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 65)
+enum v4l2_mpeg_video_hevc_profile {
+ V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN = 0,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10 = 1,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC = 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 66)
+enum v4l2_mpeg_video_hevc_level {
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1 = 0,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1 = 1,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2 = 2,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2 = 3,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1 = 4,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1 = 5,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3 = 6,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3 = 7,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1 = 8,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1 = 9,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4 = 10,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4 = 11,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1 = 12,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1 = 13,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5 = 14,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5 = 15,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1 = 16,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1 = 17,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2 = 18,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2 = 19,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6 = 20,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6 = 21,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1 = 22,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1 = 23,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2 = 24,
+ V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2 = 25,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 67)
+
+enum vl42_mpeg_vidc_video_h264_svc_nal {
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 68)
+
+enum v4l2_mpeg_vidc_video_perf_mode {
+ V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY = 1,
+ V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE = 2
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 69)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 70)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2 \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 71)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 72)
+
+/* Vendor extensions */
+#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x10000
+#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x20000
+#define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x40000
+#define V4L2_QCOM_BUF_FLAG_IDRFRAME 0x80000 /*Image is a IDR-frame*/
+#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x100000
+#define V4L2_QCOM_BUF_DATA_CORRUPT 0x200000
+#define V4L2_QCOM_BUF_DROP_FRAME 0x400000
+#define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x800000
+#define V4L2_QCOM_BUF_FLAG_EOS 0x1000000
+#define V4L2_QCOM_BUF_TS_DISCONTINUITY 0x2000000
+#define V4L2_QCOM_BUF_TS_ERROR 0x4000000
+#define V4L2_QCOM_BUF_FLAG_READONLY 0x8000000
+#define V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND 0x10000000
+#define V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP 0x20000000
+#define V4L2_MSM_BUF_FLAG_MBAFF 0x40000000
+
+/* Capabilities */
+#define V4L2_CAP_QCOM_FRAMESKIP 0x2000 /* frame skipping is supported */
+
+struct v4l2_qcom_frameskip {
+ __u64 maxframeinterval;
+ __u8 fpsvariance;
+};
+
+/* Encoder commands */
+#define V4L2_ENC_QCOM_CMD_FLUSH (4)
+
+/* Decoder commands */
+#define V4L2_DEC_QCOM_CMD_FLUSH (4)
+
+/* Flags for V4L2_DEC_QCOM_CMD_FLUSH */
+#define V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT (1 << 0)
+#define V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
+
+#define V4L2_QCOM_CMD_FLUSH_OUTPUT (1 << 0)
+#define V4L2_QCOM_CMD_FLUSH_CAPTURE (1 << 1)
+
+/* Events */
+#define V4L2_EVENT_MSM_VIDC_START (V4L2_EVENT_PRIVATE_START + 0x00001000)
+#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE (V4L2_EVENT_MSM_VIDC_START + 1)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT \
+ (V4L2_EVENT_MSM_VIDC_START + 2)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT \
+ (V4L2_EVENT_MSM_VIDC_START + 3)
+#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_MSM_VIDC_START + 4)
+#define V4L2_EVENT_MSM_VIDC_SYS_ERROR (V4L2_EVENT_MSM_VIDC_START + 5)
+#define V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE \
+ (V4L2_EVENT_MSM_VIDC_START + 6)
+#define V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER \
+ (V4L2_EVENT_MSM_VIDC_START + 7)
+#define V4L2_EVENT_MSM_VIDC_HW_OVERLOAD (V4L2_EVENT_MSM_VIDC_START + 8)
+#define V4L2_EVENT_MSM_VIDC_MAX_CLIENTS (V4L2_EVENT_MSM_VIDC_START + 9)
+#define V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED (V4L2_EVENT_MSM_VIDC_START + 10)
+
+#endif/* __MSM_V4L2_CONTROLS_H__ */
diff --git a/video.c b/video.c
new file mode 100644
index 0000000..e99ba66
--- /dev/null
+++ b/video.c
@@ -0,0 +1,619 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 Linaro Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <linux/videodev2.h>
+#include "msm-v4l2-controls.h"
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "common.h"
+
+static char *dbg_type[2] = {"OUTPUT", "CAPTURE"};
+static char *dbg_status[2] = {"ON", "OFF"};
+
+int video_open(struct instance *i, char *name)
+{
+ struct v4l2_capability cap;
+ int ret;
+
+ i->video.fd = open(name, O_RDWR, 0);
+ if (i->video.fd < 0) {
+ err("Failed to open video decoder: %s", name);
+ return -1;
+ }
+
+ memzero(cap);
+ ret = ioctl(i->video.fd, VIDIOC_QUERYCAP, &cap);
+ if (ret) {
+ err("Failed to verify capabilities");
+ return -1;
+ }
+
+ info("caps (%s): driver=\"%s\" bus_info=\"%s\" card=\"%s\" fd=0x%x",
+ name, cap.driver, cap.bus_info, cap.card, i->video.fd);
+
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) ||
+ !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) ||
+ !(cap.capabilities & V4L2_CAP_STREAMING)) {
+ err("Insufficient capabilities for video device (is %s correct?)",
+ name);
+ return -1;
+ }
+
+ return 0;
+}
+
+void video_close(struct instance *i)
+{
+ close(i->video.fd);
+}
+
+int video_set_control(struct instance *i)
+{
+ struct v4l2_control control = {0};
+ int ret;
+
+ control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+ control.value = 1;
+
+ ret = ioctl(i->video.fd, VIDIOC_S_CTRL, &control);
+
+ return ret;
+}
+
+int video_export_buf(struct instance *i, int index)
+{
+ struct video *vid = &i->video;
+ struct v4l2_exportbuffer expbuf;
+ int num_planes = CAP_PLANES;
+ int n;
+
+ for (n = 0; n < num_planes; n++) {
+ memset(&expbuf, 0, sizeof(expbuf));
+
+ expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ expbuf.index = index;
+ expbuf.flags = O_CLOEXEC | O_RDWR;
+ expbuf.plane = n;
+
+ if (ioctl(vid->fd, VIDIOC_EXPBUF, &expbuf) < 0) {
+ err("Failed to export CAPTURE buffer index%d (%s)",
+ index, strerror(errno));
+ return -1;
+ }
+
+ info("Exported CAPTURE buffer index%d (plane%d) with fd %d",
+ index, n, expbuf.fd);
+ }
+
+ return 0;
+}
+
+static int video_queue_buf(struct instance *i, int index, int l1, int l2,
+ int type, int nplanes)
+{
+ struct video *vid = &i->video;
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[2];
+ int ret;
+
+ memzero(buf);
+ memset(planes, 0, sizeof(planes));
+ buf.type = type;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = index;
+ buf.length = nplanes;
+ buf.m.planes = planes;
+
+ buf.m.planes[0].bytesused = l1;
+ buf.m.planes[1].bytesused = l2;
+
+ buf.m.planes[0].data_offset = 0;
+ buf.m.planes[1].data_offset = 0;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ buf.m.planes[0].length = vid->cap_buf_size[0];
+ } else {
+ buf.m.planes[0].length = vid->out_buf_size;
+ if (l1 == 0)
+ buf.flags |= V4L2_QCOM_BUF_FLAG_EOS;
+ }
+
+ ret = ioctl(vid->fd, VIDIOC_QBUF, &buf);
+ if (ret) {
+ err("Failed to queue buffer (index=%d) on %s (%s)",
+ buf.index,
+ dbg_type[type==V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE],
+ strerror(errno));
+ return -1;
+ }
+
+ dbg(" Queued buffer on %s queue with index %d",
+ dbg_type[type==V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE], buf.index);
+
+ return 0;
+}
+
+int video_queue_buf_out(struct instance *i, int n, int length)
+{
+ struct video *vid = &i->video;
+
+ if (n >= vid->out_buf_cnt) {
+ err("Tried to queue a non exisiting buffer");
+ return -1;
+ }
+
+ return video_queue_buf(i, n, length, 0,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ OUT_PLANES);
+}
+
+int video_queue_buf_cap(struct instance *i, int index)
+{
+ struct video *vid = &i->video;
+
+ if (index >= vid->cap_buf_cnt) {
+ err("Tried to queue a non exisiting buffer");
+ return -1;
+ }
+
+ return video_queue_buf(i, index, vid->cap_buf_size[0],
+ vid->cap_buf_size[1],
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ CAP_PLANES);
+}
+
+int video_queue_buf_cap_dmabuf(struct instance *i, int index,
+ struct drm_buffer *b)
+{
+ struct video *vid = &i->video;
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[2];
+ int ret;
+
+ if (index >= vid->cap_buf_cnt) {
+ err("Tried to queue a non exisiting buffer");
+ return -1;
+ }
+
+ memzero(buf);
+ memset(planes, 0, sizeof(planes));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ buf.memory = V4L2_MEMORY_DMABUF;
+ buf.index = index;
+ buf.length = CAP_PLANES;
+ buf.m.planes = planes;
+
+ buf.m.planes[0].m.fd = b->dbuf_fd;
+
+ buf.m.planes[0].bytesused = vid->cap_buf_size[0];
+ buf.m.planes[1].bytesused = vid->cap_buf_size[1];
+
+ buf.m.planes[0].data_offset = 0;
+ buf.m.planes[1].data_offset = 0;
+
+ buf.m.planes[0].length = vid->cap_buf_size[0];
+
+ ret = ioctl(vid->fd, VIDIOC_QBUF, &buf);
+ if (ret) {
+ err("Failed to queue buffer (index=%d) on CAPTURE (%s)",
+ buf.index, strerror(errno));
+ return -1;
+ }
+
+ dbg(" Queued buffer on %s queue with index %d",
+ dbg_type[1], buf.index);
+
+ return 0;
+}
+
+static int video_dequeue_buf(struct instance *i, struct v4l2_buffer *buf)
+{
+ struct video *vid = &i->video;
+ int ret;
+
+ ret = ioctl(vid->fd, VIDIOC_DQBUF, buf);
+ if (ret < 0) {
+ err("Failed to dequeue buffer (%d)", -errno);
+ return -errno;
+ }
+
+ dbg("Dequeued buffer on %s queue with index %d (flags:%x, bytesused:%d)",
+ dbg_type[buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE],
+ buf->index, buf->flags, buf->m.planes[0].bytesused);
+
+ return 0;
+}
+
+int video_dequeue_output(struct instance *i, int *n)
+{
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[OUT_PLANES];
+ int ret;
+
+ memzero(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.m.planes = planes;
+ buf.length = OUT_PLANES;
+
+ ret = video_dequeue_buf(i, &buf);
+ if (ret < 0)
+ return ret;
+
+ *n = buf.index;
+
+ return 0;
+}
+
+int video_dequeue_capture(struct instance *i, int *n, int *finished,
+ unsigned int *bytesused)
+{
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[CAP_PLANES];
+
+ memzero(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.m.planes = planes;
+ buf.length = CAP_PLANES;
+
+ if (video_dequeue_buf(i, &buf))
+ return -1;
+
+ *finished = 0;
+
+ if (buf.flags & V4L2_QCOM_BUF_FLAG_EOS ||
+ buf.m.planes[0].bytesused == 0)
+ *finished = 1;
+
+ *bytesused = buf.m.planes[0].bytesused;
+ *n = buf.index;
+
+ return 0;
+}
+
+int video_dequeue_capture_dmabuf(struct instance *i, int *n, int *finished,
+ unsigned int *bytesused)
+{
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[CAP_PLANES];
+
+ memzero(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ buf.memory = V4L2_MEMORY_DMABUF;
+ buf.m.planes = planes;
+ buf.length = CAP_PLANES;
+
+ if (video_dequeue_buf(i, &buf))
+ return -1;
+
+ *finished = 0;
+
+ if (buf.flags & V4L2_QCOM_BUF_FLAG_EOS ||
+ buf.m.planes[0].bytesused == 0)
+ *finished = 1;
+
+ *bytesused = buf.m.planes[0].bytesused;
+ *n = buf.index;
+
+ return 0;
+}
+
+int video_stream(struct instance *i, enum v4l2_buf_type type, int status)
+{
+ struct video *vid = &i->video;
+ int ret;
+
+ ret = ioctl(vid->fd, status, &type);
+ if (ret) {
+ err("Failed to change streaming (type=%s, status=%s)",
+ dbg_type[type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE],
+ dbg_status[status == VIDIOC_STREAMOFF]);
+ return -1;
+ }
+
+ dbg("Stream %s on %s queue", dbg_status[status==VIDIOC_STREAMOFF],
+ dbg_type[type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE]);
+
+ return 0;
+}
+
+int video_stop(struct instance *i)
+{
+ struct video *vid = &i->video;
+ struct v4l2_decoder_cmd dec;
+ int ret;
+
+#if 0
+ memzero(dec);
+ dec.cmd = V4L2_DEC_CMD_STOP;
+ ret = ioctl(vid->fd, VIDIOC_DECODER_CMD, &dec);
+ if (ret < 0) {
+ err("DECODER_CMD failed (%s)", strerror(errno));
+ return -1;
+ }
+#endif
+ ret = video_stream(i, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ VIDIOC_STREAMOFF);
+ if (ret < 0)
+ err("STREAMOFF CAPTURE queue failed (%s)", strerror(errno));
+
+ ret = video_stream(i, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ VIDIOC_STREAMOFF);
+ if (ret < 0)
+ err("STREAMOFF OUTPUT queue failed (%s)", strerror(errno));
+
+ return 0;
+}
+
+int video_setup_capture(struct instance *i, int count, int w, int h)
+{
+ struct video *vid = &i->video;
+ struct v4l2_format fmt;
+ struct v4l2_requestbuffers reqbuf;
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[CAP_PLANES];
+ int ret;
+ int n;
+
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ fmt.fmt.pix_mp.height = h;
+ fmt.fmt.pix_mp.width = w;
+ fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ ret = ioctl(vid->fd, VIDIOC_S_FMT, &fmt);
+ if (ret) {
+ err("Failed to set format (%dx%d)", w, h);
+ return -1;
+ }
+
+ vid->cap_w = fmt.fmt.pix_mp.width;
+ vid->cap_h = fmt.fmt.pix_mp.height;
+
+ vid->cap_buf_size[0] = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+ vid->cap_buf_size[1] = fmt.fmt.pix_mp.plane_fmt[1].sizeimage;
+
+ vid->cap_buf_cnt = count;
+ vid->cap_buf_cnt_min = 1;
+ vid->cap_buf_queued = 0;
+
+ dbg("video decoder buffer parameters: %dx%d plane[0]=%d plane[1]=%d",
+ fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
+ vid->cap_buf_size[0], vid->cap_buf_size[1]);
+
+ memzero(reqbuf);
+ reqbuf.count = vid->cap_buf_cnt;
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ reqbuf.memory = V4L2_MEMORY_MMAP;
+
+ ret = ioctl(vid->fd, VIDIOC_REQBUFS, &reqbuf);
+ if (ret != 0) {
+ err("REQBUFS failed on CAPTURE queue (%s)", strerror(errno));
+ return -1;
+ }
+
+ info("Number of CAPTURE buffers is %d (requested %d, extra %d)",
+ reqbuf.count, vid->cap_buf_cnt, 0);
+
+ vid->cap_buf_cnt = reqbuf.count;
+
+ for (n = 0; n < vid->cap_buf_cnt; n++) {
+ memzero(buf);
+ memset(planes, 0, sizeof(planes));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = n;
+ buf.m.planes = planes;
+ buf.length = CAP_PLANES;
+
+ ret = ioctl(vid->fd, VIDIOC_QUERYBUF, &buf);
+ if (ret != 0) {
+ err("QUERYBUF failed on CAPTURE queue (%s)",
+ strerror(errno));
+ return -1;
+ }
+
+ vid->cap_buf_off[n][0] = buf.m.planes[0].m.mem_offset;
+
+ vid->cap_buf_addr[n][0] = mmap(NULL, buf.m.planes[0].length,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ vid->fd,
+ buf.m.planes[0].m.mem_offset);
+
+ if (vid->cap_buf_addr[n][0] == MAP_FAILED) {
+ err("Failed to MMAP CAPTURE buffer on plane0");
+ return -1;
+ }
+
+ vid->cap_buf_size[0] = buf.m.planes[0].length;
+ }
+
+ dbg("Succesfully mmapped %d CAPTURE buffers", n);
+
+ return 0;
+}
+
+int video_setup_capture_dmabuf(struct instance *i, int count, int w, int h)
+{
+ struct video *vid = &i->video;
+ struct v4l2_format fmt;
+ struct v4l2_requestbuffers reqbuf;
+ int ret;
+
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ fmt.fmt.pix_mp.height = h;
+ fmt.fmt.pix_mp.width = w;
+ fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ ret = ioctl(vid->fd, VIDIOC_S_FMT, &fmt);
+ if (ret) {
+ err("Failed to set format (%dx%d)", w, h);
+ return -1;
+ }
+
+ vid->cap_w = fmt.fmt.pix_mp.width;
+ vid->cap_h = fmt.fmt.pix_mp.height;
+
+ vid->cap_buf_size[0] = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+ vid->cap_buf_size[1] = fmt.fmt.pix_mp.plane_fmt[1].sizeimage;
+
+ vid->cap_buf_cnt = count;
+ vid->cap_buf_cnt_min = 1;
+ vid->cap_buf_queued = 0;
+
+ dbg("video decoder buffer parameters: %dx%d plane[0]=%d plane[1]=%d",
+ fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
+ vid->cap_buf_size[0], vid->cap_buf_size[1]);
+
+ memzero(reqbuf);
+ reqbuf.count = vid->cap_buf_cnt;
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ reqbuf.memory = V4L2_MEMORY_DMABUF;
+
+ ret = ioctl(vid->fd, VIDIOC_REQBUFS, &reqbuf);
+ if (ret != 0) {
+ err("REQBUFS failed on CAPTURE queue (%s)", strerror(errno));
+ return -1;
+ }
+
+ info("Number of CAPTURE buffers is %d (requested %d, extra %d)",
+ reqbuf.count, vid->cap_buf_cnt, 0);
+
+ vid->cap_buf_cnt = reqbuf.count;
+
+ dbg("Succesfully requested %d dmabuf CAPTURE buffers", vid->cap_buf_cnt);
+
+ return 0;
+}
+
+int video_setup_output(struct instance *i, unsigned long codec,
+ unsigned int size, int count)
+{
+ struct video *vid = &i->video;
+ struct v4l2_format fmt, try_fmt, g_fmt;
+ struct v4l2_requestbuffers reqbuf;
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[OUT_PLANES];
+ int ret;
+ int n;
+
+ memzero(try_fmt);
+ try_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ try_fmt.fmt.pix_mp.width = i->width;
+ try_fmt.fmt.pix_mp.height = i->height;
+ try_fmt.fmt.pix_mp.pixelformat = codec;
+
+ ret = ioctl(vid->fd, VIDIOC_TRY_FMT, &try_fmt);
+ if (ret) {
+ err("Failed to try format on OUTPUT (%s)", strerror(errno));
+ }
+
+ dbg("Try OUTPUT format sizeimage=%u",
+ try_fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
+
+ memzero(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ fmt.fmt.pix_mp.width = i->width;
+ fmt.fmt.pix_mp.height = i->height;
+ fmt.fmt.pix_mp.pixelformat = codec;
+
+ ret = ioctl(vid->fd, VIDIOC_S_FMT, &fmt);
+ if (ret) {
+ err("Failed to set format on OUTPUT (%s)", strerror(errno));
+ return -1;
+ }
+
+ dbg("Setup decoding OUTPUT buffer size=%u (requested=%u)",
+ fmt.fmt.pix_mp.plane_fmt[0].sizeimage, size);
+
+ 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.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 {
+ err("Get format sizeimage is %d",
+ g_fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
+ }
+
+ memzero(reqbuf);
+ reqbuf.count = count;
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ reqbuf.memory = V4L2_MEMORY_MMAP;
+
+ ret = ioctl(vid->fd, VIDIOC_REQBUFS, &reqbuf);
+ if (ret) {
+ err("REQBUFS failed on OUTPUT queue");
+ return -1;
+ }
+
+ vid->out_buf_cnt = reqbuf.count;
+
+ dbg("Number of video decoder OUTPUT buffers is %d (requested %d)",
+ vid->out_buf_cnt, count);
+
+ for (n = 0; n < vid->out_buf_cnt; n++) {
+ memzero(buf);
+ memset(planes, 0, sizeof(planes));
+ buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = n;
+ buf.m.planes = planes;
+ buf.length = OUT_PLANES;
+
+ ret = ioctl(vid->fd, VIDIOC_QUERYBUF, &buf);
+ if (ret != 0) {
+ err("QUERYBUF failed on OUTPUT buffer");
+ return -1;
+ }
+
+ vid->out_buf_off[n] = buf.m.planes[0].m.mem_offset;
+ vid->out_buf_size = buf.m.planes[0].length;
+
+ vid->out_buf_addr[n] = mmap(NULL, buf.m.planes[0].length,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ vid->fd,
+ buf.m.planes[0].m.mem_offset);
+
+ if (vid->out_buf_addr[n] == MAP_FAILED) {
+ err("Failed to MMAP OUTPUT buffer");
+ return -1;
+ }
+
+ vid->out_buf_flag[n] = 0;
+ }
+
+ dbg("Succesfully mmapped %d OUTPUT buffers", n);
+
+ return 0;
+}
+
diff --git a/video.h b/video.h
new file mode 100644
index 0000000..15033a1
--- /dev/null
+++ b/video.h
@@ -0,0 +1,73 @@
+/*
+ * V4L2 Codec decoding example application
+ * Kamil Debski <k.debski@samsung.com>
+ *
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 Linaro Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef INCLUDE_VIDEO_H
+#define INCLUDE_VIDEO_H
+
+#include "common.h"
+
+/* Open the video decoder device */
+int video_open(struct instance *i, char *name);
+
+/* Close the video decoder devices */
+void video_close(struct instance *i);
+
+/* Setup the OUTPUT queue. The size determines the size for the stream
+ * buffer. This is the maximum size a single compressed frame can have.
+ * The count is the number of the stream buffers to allocate. */
+int video_setup_output(struct instance *i, unsigned long codec,
+ unsigned int size, int count);
+
+/* Setup the CAPTURE queue. The argument extra_buf means the number of extra
+ * buffers that should added to the minimum number of buffers required
+ * by MFC. The final number of buffers allocated is stored in the instance
+ * structure. */
+int video_setup_capture(struct instance *i, int extra_buf, int w, int h);
+int video_setup_capture_dmabuf(struct instance *i, int count, int w, int h);
+
+/* Queue OUTPUT buffer */
+int video_queue_buf_out(struct instance *i, int n, int length);
+
+/* Queue CAPTURE buffer */
+int video_queue_buf_cap(struct instance *i, int n);
+int video_queue_buf_cap_dmabuf(struct instance *i, int index,
+ struct drm_buffer *b);
+
+/* Control MFC streaming */
+int video_stream(struct instance *i, enum v4l2_buf_type type, int status);
+
+int video_export_buf(struct instance *i, int index);
+
+/* Dequeue a buffer, the structure *buf is used to return the parameters of the
+ * dequeued buffer. */
+int video_dequeue_output(struct instance *i, int *n);
+int video_dequeue_capture(struct instance *i, int *n, int *finished,
+ unsigned int *bytesused);
+int video_dequeue_capture_dmabuf(struct instance *i, int *n, int *finished,
+ unsigned int *bytesused);
+
+int video_set_control(struct instance *i);
+
+int video_stop(struct instance *i);
+
+#endif /* INCLUDE_VIDEO_H */
+