blob: 116b5072e989e050ac30ff654a4677bae79d246c [file] [log] [blame]
henryhsu58be50c2014-10-30 11:49:19 +08001/* Copyright 2014 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
Wu-Cheng Lice8947e2014-11-13 17:34:16 +08006#include <assert.h>
7#include <errno.h>
8#include <linux/videodev2.h>
9#include <pthread.h>
henryhsu58be50c2014-10-30 11:49:19 +080010#include <unistd.h>
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080011#include <stdbool.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/queue.h>
henryhsu58be50c2014-10-30 11:49:19 +080016#include <sys/syscall.h>
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080017#include "config.h" /* For HAVE_VISIBILITY */
henryhsu58be50c2014-10-30 11:49:19 +080018#include "libv4l-plugin.h"
Alpha Linfa5caae2014-11-17 09:48:35 +080019#include "libvpu/rk_vepu_debug.h"
Wu-Cheng Lidcec4332014-11-13 15:49:21 +080020#include "libvpu/rk_vepu_interface.h"
henryhsu58be50c2014-10-30 11:49:19 +080021
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080022#define VLOG(log_level, str, ...) ((g_log_level >= log_level) ? \
23 (void) fprintf(stderr, "%s: " str "\n", __func__, ##__VA_ARGS__) \
24 : (void) 0)
25
26#define VLOG_FD(log_level, str, ...) ((g_log_level >= log_level) ? \
27 (void) fprintf(stderr, \
28 "%s: fd=%d. " str "\n", __func__, fd, ##__VA_ARGS__) : (void) 0)
29
30#define SYS_IOCTL(fd, cmd, arg) ({ \
31 int ret = syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), \
32 (void *)(arg)); \
Hirokazu Hondacfb9e182017-07-19 17:54:08 +090033 if (g_log_level >= 2 || (ret && errno != EAGAIN && \
34 (cmd != VIDIOC_ENUM_FMT || errno != EINVAL))) \
henryhsuc7c06f92014-11-24 15:57:08 +080035 fprintf(stderr, "SYS_ioctl: %s(%lu): fd=%d, ret=%d, errno=%d\n",\
36 v4l_cmd2str(cmd), _IOC_NR((unsigned long)cmd), fd, ret, \
37 errno); \
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080038 ret; \
39 })
henryhsu58be50c2014-10-30 11:49:19 +080040
41#if HAVE_VISIBILITY
42#define PLUGIN_PUBLIC __attribute__ ((__visibility__("default")))
43#else
44#define PLUGIN_PUBLIC
45#endif
46
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +080047#define RK3288_VPU_NAME "rk3288-vpu-enc"
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080048#define DEFAULT_FRAME_RATE 30
49#define DEFAULT_BITRATE 1000000
henryhsuc7c06f92014-11-24 15:57:08 +080050#define PENDING_BUFFER_QUEUE_SIZE VIDEO_MAX_FRAME
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080051
henryhsuc7c06f92014-11-24 15:57:08 +080052/*
53 * struct pending_buffer - A v4l2 buffer pending for QBUF.
54 * @buffer: v4l2 buffer for QBUF.
55 * @planes: plane info of v4l2 buffer.
56 * @next_runtime_param: runtime parameters like framerate, bitrate, and
57 * keyframe for the next buffer.
58 */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080059struct pending_buffer {
60 struct v4l2_buffer buffer;
61 struct v4l2_plane planes[VIDEO_MAX_PLANES];
henryhsuc7c06f92014-11-24 15:57:08 +080062 struct rk_vepu_runtime_param next_runtime_param;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080063};
henryhsuc7c06f92014-11-24 15:57:08 +080064
65/*
66 * struct pending_buffer_queue - a ring buffer of pending buffers.
67 * @count: the number of buffers stored in the array.
68 * @front: the index of the first ready buffer.
69 * @buf_array: pending buffer array.
70 */
71struct pending_buffer_queue {
72 uint32_t count;
73 int32_t front;
74 struct pending_buffer buf_array[PENDING_BUFFER_QUEUE_SIZE];
75};
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080076
77/*
78 * struct encoder_context - the context of an encoder instance.
79 * @enc: Encoder instance returned from rk_vepu_create().
80 * @mutex: The mutex to protect encoder_context.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080081 * @output_streamon_type: Type of output interface when it streams on.
82 * @capture_streamon_type: Type of capture interface when it streams on.
henryhsuc7c06f92014-11-24 15:57:08 +080083 * @init_param: Encoding parameters like input format, resolution, and etc.
84 * These parameters will be passed to encoder at libvpu
85 * initialization.
86 * @runtime_param: Runtime parameters like framerate, bitrate, and
87 * keyframe. This is only used for receiving ext_ctrls
88 * before streamon and pending buffer queue is empty.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080089 * @pending_buffers: The pending v4l2 buffers waiting for the encoding
90 * configuration. After a previous buffer is dequeued,
91 * one buffer from the queue can be queued.
92 * @can_qbuf: Indicate that we can queue one source buffer. This is true only
93 * when the parameters to pass together with the source buffer are
94 * ready; those params are received on dequeing the previous
95 * destination buffer.
96 * @get_param_payload: Payload of V4L2_CID_PRIVATE_RK3288_GET_PARAMS. This is
97 * used to update the encoder configuration by
98 * rk_vepu_update_config().
99 * @get_param_payload_size: The size of get_param_payload.
100 * @v4l2_ctrls: v4l2 controls for VIDIOC_S_EXT_CTRLS.
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900101 * @flushing: Indicate the encoder is flushing frame.
102 * @eos_buffer: The last buffer to be flushed. Reset to NULL after the buffer
103 * is enqueued to the driver.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800104 */
105struct encoder_context {
106 void *enc;
107 pthread_mutex_t mutex;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800108 enum v4l2_buf_type output_streamon_type;
109 enum v4l2_buf_type capture_streamon_type;
henryhsuc7c06f92014-11-24 15:57:08 +0800110 struct rk_vepu_init_param init_param;
111 struct rk_vepu_runtime_param runtime_param;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800112 struct pending_buffer_queue pending_buffers;
113 bool can_qbuf;
114 void *get_param_payload;
115 size_t get_param_payload_size;
116 struct v4l2_ext_control v4l2_ctrls[MAX_NUM_GET_CONFIG_CTRLS];
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900117 bool flushing;
118 struct pending_buffer *eos_buffer;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800119};
120
121static void *plugin_init(int fd);
122static void plugin_close(void *dev_ops_priv);
123static int plugin_ioctl(void *dev_ops_priv, int fd, unsigned long int cmd,
124 void *arg);
125
126/* Functions to handle various ioctl. */
127static int ioctl_streamon_locked(
128 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
129static int ioctl_streamoff_locked(
130 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
131static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
132 struct v4l2_buffer *buffer);
133static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
134 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800135static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
136 struct v4l2_ext_controls *ext_ctrls);
137static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
138 struct v4l2_streamparm *parms);
139static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
140 struct v4l2_requestbuffers *reqbufs);
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900141static int ioctl_encoder_cmd_locked(struct encoder_context *ctx, int fd,
142 struct v4l2_encoder_cmd *argp);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800143
144/* Helper functions to manipulate the pending buffer queue. */
145
henryhsuc7c06f92014-11-24 15:57:08 +0800146static void queue_init(struct pending_buffer_queue *queue);
147static bool queue_empty(struct pending_buffer_queue *queue);
148static bool queue_full(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800149/* Insert a buffer to the tail of the queue. */
henryhsuc7c06f92014-11-24 15:57:08 +0800150static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800151 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800152/* Remove a buffer from the head of the queue. */
153static void queue_pop_front(struct pending_buffer_queue *queue);
154static struct pending_buffer *queue_front(struct pending_buffer_queue *queue);
155static struct pending_buffer *queue_back(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800156
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800157/* Returns true if the fd is Rockchip encoder device. */
158bool is_rockchip_encoder(int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800159/* Set encoder configuration to the driver. */
henryhsuc7c06f92014-11-24 15:57:08 +0800160int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800161 uint32_t buffer_index, size_t num_ctrls, uint32_t ctrls_ids[],
162 void **payloads, uint32_t payload_sizes[]);
163/* QBUF a buffer from the pending buffer queue if it is not empty. */
henryhsuc7c06f92014-11-24 15:57:08 +0800164static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
165 int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800166/* Get the encoder parameters using G_FMT and initialize libvpu. */
167static int initialize_libvpu(struct encoder_context *ctx, int fd);
168/* Return the string represenation of a libv4l command for debugging. */
169static const char *v4l_cmd2str(unsigned long int cmd);
Alpha Linfa5caae2014-11-17 09:48:35 +0800170/* Get the log level from the environment variable LIBV4L_PLUGIN_LOG_LEVEL. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800171static void get_log_level();
172static pthread_once_t g_get_log_level_once = PTHREAD_ONCE_INIT;
173
henryhsu58be50c2014-10-30 11:49:19 +0800174static void *plugin_init(int fd)
175{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800176 int ret;
177 struct v4l2_query_ext_ctrl ext_ctrl;
178
179 pthread_once(&g_get_log_level_once, get_log_level);
180
181 VLOG_FD(1, "");
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800182 if (!is_rockchip_encoder(fd))
183 return NULL;
184
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800185 struct encoder_context *ctx = (struct encoder_context *)
186 calloc(1, sizeof(struct encoder_context));
187 if (ctx == NULL) {
188 errno = ENOMEM;
189 goto fail;
190 }
191 ret = pthread_mutex_init(&ctx->mutex, NULL);
192 if (ret)
193 goto fail;
henryhsuc7c06f92014-11-24 15:57:08 +0800194 queue_init(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800195
196 memset(&ext_ctrl, 0, sizeof(ext_ctrl));
197 ext_ctrl.id = V4L2_CID_PRIVATE_RK3288_GET_PARAMS;
198 ret = SYS_IOCTL(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl);
199 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800200 goto fail;
201 }
202 ctx->get_param_payload_size = ext_ctrl.elem_size;
203 ctx->get_param_payload = calloc(1, ctx->get_param_payload_size);
204 if (ctx->get_param_payload == NULL) {
205 errno = ENOMEM;
206 goto fail;
207 }
henryhsuc7c06f92014-11-24 15:57:08 +0800208 ctx->runtime_param.framerate_numer = DEFAULT_FRAME_RATE;
209 ctx->runtime_param.framerate_denom = 1;
210 ctx->runtime_param.bitrate = DEFAULT_BITRATE;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800211 VLOG_FD(1, "Success. ctx=%p", ctx);
212 return ctx;
213
214fail:
215 plugin_close(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800216 return NULL;
217}
218
219static void plugin_close(void *dev_ops_priv)
220{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800221 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
222
223 VLOG(1, "ctx=%p", ctx);
224 if (ctx == NULL)
225 return;
226
227 pthread_mutex_lock(&ctx->mutex);
228 if (ctx->enc)
229 rk_vepu_deinit(ctx->enc);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800230 free(ctx->get_param_payload);
231 ctx->get_param_payload = NULL;
232 pthread_mutex_unlock(&ctx->mutex);
233 pthread_mutex_destroy(&ctx->mutex);
234
235 free(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800236}
237
238static int plugin_ioctl(void *dev_ops_priv, int fd,
239 unsigned long int cmd, void *arg)
240{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800241 int ret;
242 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
243
244 VLOG_FD(1, "%s(%lu)", v4l_cmd2str(cmd), _IOC_NR(cmd));
245
246 pthread_mutex_lock(&ctx->mutex);
247 switch (cmd) {
248 case VIDIOC_STREAMON:
henryhsuc7c06f92014-11-24 15:57:08 +0800249 ret = ioctl_streamon_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800250 break;
251
252 case VIDIOC_STREAMOFF:
henryhsuc7c06f92014-11-24 15:57:08 +0800253 ret = ioctl_streamoff_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800254 break;
255
256 case VIDIOC_QBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800257 ret = ioctl_qbuf_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800258 break;
259
260 case VIDIOC_DQBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800261 ret = ioctl_dqbuf_locked(ctx, fd, arg);
262 break;
263
264 case VIDIOC_S_EXT_CTRLS:
265 ret = ioctl_s_ext_ctrls_locked(ctx, fd, arg);
266 break;
267
268 case VIDIOC_S_PARM:
269 ret = ioctl_s_parm_locked(ctx, fd, arg);
270 break;
271
272 case VIDIOC_REQBUFS:
273 ret = ioctl_reqbufs_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800274 break;
275
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900276 case VIDIOC_ENCODER_CMD:
277 ret = ioctl_encoder_cmd_locked(ctx, fd, arg);
278 break;
279
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800280 default:
281 ret = SYS_IOCTL(fd, cmd, arg);
282 break;
283 }
284 pthread_mutex_unlock(&ctx->mutex);
285 return ret;
286}
287
288static int ioctl_streamon_locked(
289 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
290{
291 int ret = SYS_IOCTL(fd, VIDIOC_STREAMON, type);
292 if (ret)
293 return ret;
294
295 if (V4L2_TYPE_IS_OUTPUT(*type))
296 ctx->output_streamon_type = *type;
297 else
298 ctx->capture_streamon_type = *type;
299 if (ctx->output_streamon_type && ctx->capture_streamon_type) {
300 ret = initialize_libvpu(ctx, fd);
301 if (ret)
302 return ret;
303 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800304 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800305 }
306 return 0;
307}
308
309static int ioctl_streamoff_locked(
310 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
311{
312 int ret = SYS_IOCTL(fd, VIDIOC_STREAMOFF, type);
313 if (ret)
314 return ret;
315
316 if (V4L2_TYPE_IS_OUTPUT(*type))
317 ctx->output_streamon_type = 0;
318 else
319 ctx->capture_streamon_type = 0;
320 return 0;
321}
322
323static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
324 struct v4l2_buffer *buffer)
325{
326 size_t num_ctrls = 0;
327 uint32_t *ctrl_ids = NULL, *payload_sizes = NULL;
328 void **payloads = NULL;
329 int ret;
330
331 if (!V4L2_TYPE_IS_OUTPUT(buffer->type)) {
332 return SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
333 }
334
335 if (!ctx->can_qbuf) {
336 VLOG_FD(1, "Put buffer (%d) in the pending queue.",
337 buffer->index);
338 /*
339 * The last frame is not encoded yet. Put the buffer to the
340 * pending queue.
341 */
henryhsuc7c06f92014-11-24 15:57:08 +0800342 return queue_push_back(&ctx->pending_buffers, buffer);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800343 }
344 /* Get the encoder configuration from the library. */
345 if (rk_vepu_get_config(ctx->enc, &num_ctrls, &ctrl_ids, &payloads,
346 &payload_sizes)) {
347 VLOG_FD(0, "rk_vepu_get_config failed");
348 return -EIO;
349 }
350 /* Set the encoder configuration to the driver. */
henryhsuc7c06f92014-11-24 15:57:08 +0800351 ret = set_encoder_config_locked(ctx, fd, buffer->index, num_ctrls, ctrl_ids,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800352 payloads, payload_sizes);
353 if (ret)
354 return ret;
355
Heng-Ruey Hsu61eb2ec2016-05-20 18:11:53 +0800356 buffer->config_store = buffer->index + 1;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800357 ret = SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
358 if (ret == 0)
359 ctx->can_qbuf = false;
360 else
361 VLOG(0, "QBUF failed. errno=%d", errno);
362 return ret;
363}
364
365static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
366 struct v4l2_buffer *buffer)
367{
368 struct v4l2_ext_controls ext_ctrls;
369 struct v4l2_ext_control v4l2_ctrl;
370 int ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800371 uint32_t bytesused;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800372
373 if (V4L2_TYPE_IS_OUTPUT(buffer->type)) {
374 return SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
375 }
376
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800377 ret = SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
378 if (ret)
379 return ret;
380
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900381 /* Get the encoder configuration and update the library.
382 * Because we dequeue a null frame to indicate flush is finished, do not
383 * update the config with this frame. */
henryhsuc7c06f92014-11-24 15:57:08 +0800384 bytesused = V4L2_TYPE_IS_MULTIPLANAR(buffer->type) ?
385 buffer->m.planes[0].bytesused : buffer->bytesused;
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900386 if (bytesused) {
387 memset(ctx->get_param_payload, 0, ctx->get_param_payload_size);
388 memset(&v4l2_ctrl, 0, sizeof(v4l2_ctrl));
389 v4l2_ctrl.id = V4L2_CID_PRIVATE_RK3288_GET_PARAMS;
390 v4l2_ctrl.size = ctx->get_param_payload_size;
391 v4l2_ctrl.ptr = ctx->get_param_payload;
392 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
393 /* TODO: change this to config_store after the header is
394 * updated. */
395 ext_ctrls.ctrl_class = 0;
396 ext_ctrls.count = 1;
397 ext_ctrls.controls = &v4l2_ctrl;
398 ret = SYS_IOCTL(fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls);
399 if (ret)
400 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800401
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900402 if (rk_vepu_update_config(ctx->enc, v4l2_ctrl.ptr,
403 v4l2_ctrl.size, bytesused)) {
404 VLOG_FD(0, "rk_vepu_update_config failed.");
405 return -EIO;
406 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800407 }
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900408
409 /* When flushing buffer, we don't queue any new buffer.
410 * So we ignore checking can_qbuf and trying to qbuf new buffer. */
411 assert(ctx->flushing || !ctx->can_qbuf);
412 if (buffer->flags & V4L2_BUF_FLAG_LAST)
413 ctx->flushing = false;
414 if (ctx->flushing)
415 return 0;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800416 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800417 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800418}
419
henryhsuc7c06f92014-11-24 15:57:08 +0800420static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
421 struct v4l2_ext_controls *ext_ctrls)
422{
423 size_t i;
424 struct rk_vepu_runtime_param *runtime_param_ptr;
425
426 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
427 /*
428 * If buffer queue is empty, update parameters directly.
429 * If buffer queue is not empty, save parameters to the last buffer. And
430 * these values will be sent again when the buffer is ready to deliver.
431 */
432 if (!no_pending_buffer) {
433 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
434 runtime_param_ptr = &element->next_runtime_param;
435 } else {
436 runtime_param_ptr = &ctx->runtime_param;
437 }
438
439 /*
440 * Check each extension control to update keyframe and bitrate
441 * parameters.
442 */
443 for (i = 0; i < ext_ctrls->count; i++) {
444 switch (ext_ctrls->controls[i].id) {
Heng-Ruey Hsu61eb2ec2016-05-20 18:11:53 +0800445 case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
446 runtime_param_ptr->keyframe_request = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800447 break;
448 case V4L2_CID_MPEG_VIDEO_BITRATE:
449 runtime_param_ptr->bitrate = ext_ctrls->controls[i].value;
450 break;
451 default:
452 break;
453 }
454 }
455
456 if (no_pending_buffer && ctx->enc) {
457 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
458 VLOG_FD(0, "rk_vepu_update_parameter failed.");
459 return -EIO;
460 }
461 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
462 }
463 /* Driver should ignore keyframe and bitrate controls */
464 return SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, ext_ctrls);
465}
466
467static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
468 struct v4l2_streamparm *parms)
469{
470 if (V4L2_TYPE_IS_OUTPUT(parms->type)
471 && parms->parm.output.timeperframe.denominator) {
472 struct rk_vepu_runtime_param *runtime_param_ptr;
473 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
474 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
475
476 runtime_param_ptr = no_pending_buffer ? &ctx->runtime_param :
477 &element->next_runtime_param;
478 runtime_param_ptr->framerate_numer =
479 parms->parm.output.timeperframe.denominator;
480 runtime_param_ptr->framerate_denom =
481 parms->parm.output.timeperframe.numerator;
482
483 if (!no_pending_buffer || !ctx->enc)
484 return 0;
485 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
486 VLOG_FD(0, "rk_vepu_update_parameter failed.");
487 return -EIO;
488 }
489 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
490 return 0;
491 }
492 return SYS_IOCTL(fd, VIDIOC_S_PARM, parms);
493}
494
495static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
496 struct v4l2_requestbuffers *reqbufs)
497{
498 int ret = SYS_IOCTL(fd, VIDIOC_REQBUFS, reqbufs);
499 if (ret)
500 return ret;
501 queue_init(&ctx->pending_buffers);
502 return 0;
503}
504
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900505static int ioctl_encoder_cmd_locked(struct encoder_context *ctx, int fd,
506 struct v4l2_encoder_cmd *argp)
507{
508 if (argp->cmd == V4L2_ENC_CMD_STOP) {
509 if (ctx->flushing) {
510 VLOG_FD(0, "previous stop command is not handled yet.");
511 return -EINVAL;
512 }
513 ctx->flushing = true;
514 /* If there is any pending buffer, then send the stop command
515 * after we enqueue the last buffer. Otherwise, we just send
516 * the command to the kernel instantly. */
517 if (!queue_empty(&ctx->pending_buffers)) {
518 ctx->eos_buffer = queue_back(&ctx->pending_buffers);
519 return 0;
520 }
521 }
522 return SYS_IOCTL(fd, VIDIOC_ENCODER_CMD, argp);
523}
524
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800525bool is_rockchip_encoder(int fd) {
526 struct v4l2_capability cap;
527 memset(&cap, 0, sizeof(cap));
528 int ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
529 if (ret)
530 return false;
Alpha Linfa5caae2014-11-17 09:48:35 +0800531 return strcmp(RK3288_VPU_NAME, (const char *)cap.driver) == 0;
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800532}
533
henryhsuc7c06f92014-11-24 15:57:08 +0800534int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800535 uint32_t buffer_index, size_t num_ctrls, uint32_t ctrl_ids[],
henryhsuc7c06f92014-11-24 15:57:08 +0800536 void **payloads, uint32_t payload_sizes[])
537{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800538 size_t i;
539 struct v4l2_ext_controls ext_ctrls;
540
541 if (num_ctrls <= 0)
542 return 0;
543
544 assert(num_ctrls <= MAX_NUM_GET_CONFIG_CTRLS);
henryhsuc7c06f92014-11-24 15:57:08 +0800545 if (num_ctrls > MAX_NUM_GET_CONFIG_CTRLS) {
546 VLOG_FD(0, "The number of controls exceeds limit.");
547 return -EIO;
548 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800549 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
550 /* TODO: change this to config_store after the header is updated. */
551 ext_ctrls.ctrl_class = buffer_index + 1;
552 ext_ctrls.count = num_ctrls;
553 ext_ctrls.controls = ctx->v4l2_ctrls;
554 memset(ctx->v4l2_ctrls, 0, sizeof(ctx->v4l2_ctrls));
555 for (i = 0; i < num_ctrls; ++i) {
556 ctx->v4l2_ctrls[i].id = ctrl_ids[i];
557 ctx->v4l2_ctrls[i].ptr = payloads[i];
558 ctx->v4l2_ctrls[i].size = payload_sizes[i];
559 }
560 int ret = SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, &ext_ctrls);
561 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800562 return ret;
563 }
564 return 0;
565}
566
henryhsuc7c06f92014-11-24 15:57:08 +0800567static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
568 int fd)
569{
570 if (!queue_empty(&ctx->pending_buffers)) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800571 int ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800572 struct pending_buffer *element = queue_front(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800573 VLOG_FD(1, "QBUF a buffer (%d) from the pending queue.",
574 element->buffer.index);
henryhsuc7c06f92014-11-24 15:57:08 +0800575 if (rk_vepu_update_parameter(ctx->enc, &element->next_runtime_param)) {
576 VLOG_FD(0, "rk_vepu_update_parameter failed.");
577 return -EIO;
578 }
Tomasz Figaaed2ed92015-02-25 14:05:53 +0900579 memset(&element->next_runtime_param, 0,
580 sizeof(element->next_runtime_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800581 ret = ioctl_qbuf_locked(ctx, fd, &element->buffer);
582 if (ret)
583 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800584 queue_pop_front(&ctx->pending_buffers);
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900585 /* QBUF the last buffer to be flushed, send stop command. */
586 if (element == ctx->eos_buffer) {
587 ctx->eos_buffer = NULL;
588 struct v4l2_encoder_cmd argp = {
589 .cmd = V4L2_ENC_CMD_STOP,
590 };
591 return SYS_IOCTL(fd, VIDIOC_ENCODER_CMD, &argp);
592 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800593 }
594 return 0;
595}
596
henryhsuc7c06f92014-11-24 15:57:08 +0800597static int initialize_libvpu(struct encoder_context *ctx, int fd)
598{
599 struct rk_vepu_init_param init_param;
600 memset(&init_param, 0, sizeof(init_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800601
Alpha Linfa5caae2014-11-17 09:48:35 +0800602 /* Get the input format. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800603 struct v4l2_format format;
604 memset(&format, 0, sizeof(format));
605 format.type = ctx->output_streamon_type;
606 int ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
Alpha Linfa5caae2014-11-17 09:48:35 +0800607 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800608 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800609 init_param.input_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800610
Alpha Linfa5caae2014-11-17 09:48:35 +0800611 /* Get the output format. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800612 memset(&format, 0, sizeof(format));
613 format.type = ctx->capture_streamon_type;
614 ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
Alpha Linfa5caae2014-11-17 09:48:35 +0800615 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800616 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800617 init_param.output_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800618
Alpha Linfa5caae2014-11-17 09:48:35 +0800619 /* Get the cropped size. */
620 struct v4l2_crop crop;
621 memset(&crop, 0, sizeof(crop));
622 crop.type = ctx->output_streamon_type;
623 ret = SYS_IOCTL(fd, VIDIOC_G_CROP, &crop);
624 if (ret)
625 return ret;
626 init_param.width = crop.c.width;
627 init_param.height = crop.c.height;
628
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800629 /*
630 * If the encoder library has initialized and parameters have not
631 * changed, skip the initialization.
632 */
henryhsuc7c06f92014-11-24 15:57:08 +0800633 if (ctx->enc && memcmp(&init_param, &ctx->init_param, sizeof(init_param))) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800634 rk_vepu_deinit(ctx->enc);
henryhsuc7c06f92014-11-24 15:57:08 +0800635 ctx->enc = NULL;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800636 }
henryhsuc7c06f92014-11-24 15:57:08 +0800637 if (!ctx->enc) {
638 memcpy(&ctx->init_param, &init_param, sizeof(init_param));
639 ctx->enc = rk_vepu_init(&init_param);
640 if (ctx->enc == NULL) {
641 VLOG_FD(0, "Failed to initialize encoder library.");
642 return -EIO;
643 }
644 }
645 if (rk_vepu_update_parameter(ctx->enc, &ctx->runtime_param)) {
646 VLOG_FD(0, "rk_vepu_update_parameter failed.");
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800647 return -EIO;
648 }
henryhsuc7c06f92014-11-24 15:57:08 +0800649 memset(&ctx->runtime_param, 0, sizeof(struct rk_vepu_runtime_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800650 return 0;
651}
652
henryhsuc7c06f92014-11-24 15:57:08 +0800653static void queue_init(struct pending_buffer_queue *queue)
654{
655 memset(queue, 0, sizeof(struct pending_buffer_queue));
656}
657
658static bool queue_empty(struct pending_buffer_queue *queue)
659{
660 return queue->count == 0;
661}
662
663static bool queue_full(struct pending_buffer_queue *queue)
664{
665 return queue->count == PENDING_BUFFER_QUEUE_SIZE;
666}
667
668static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800669 struct v4l2_buffer *buffer)
670{
henryhsuc7c06f92014-11-24 15:57:08 +0800671 if (queue_full(queue))
672 return -ENOMEM;
673 int rear = (queue->front + queue->count) % PENDING_BUFFER_QUEUE_SIZE;
674 queue->count++;
675 struct pending_buffer *entry = &queue->buf_array[rear];
676 memset(entry, 0, sizeof(struct pending_buffer));
677
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800678 memcpy(&entry->buffer, buffer, sizeof(*buffer));
679 if (V4L2_TYPE_IS_MULTIPLANAR(buffer->type)) {
680 memset(entry->planes, 0,
681 sizeof(struct v4l2_plane) * VIDEO_MAX_PLANES);
682 memcpy(entry->planes, buffer->m.planes,
683 sizeof(struct v4l2_plane) * buffer->length);
684 entry->buffer.m.planes = entry->planes;
685 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800686 return 0;
687}
688
henryhsuc7c06f92014-11-24 15:57:08 +0800689static void queue_pop_front(struct pending_buffer_queue *queue)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800690{
henryhsuc7c06f92014-11-24 15:57:08 +0800691 assert(!queue_empty(queue));
692 queue->count--;
693 queue->front = (queue->front + 1) % PENDING_BUFFER_QUEUE_SIZE;
694}
695
696static struct pending_buffer *queue_front(struct pending_buffer_queue *queue)
697{
698 if (queue_empty(queue))
699 return NULL;
700 return &queue->buf_array[queue->front];
701}
702
703static struct pending_buffer *queue_back(struct pending_buffer_queue *queue)
704{
705 if (queue_empty(queue))
706 return NULL;
707 return &queue->buf_array[(queue->front + queue->count - 1) %
708 PENDING_BUFFER_QUEUE_SIZE];
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800709}
710
711static void get_log_level()
712{
713 char *log_level_str = getenv("LIBV4L_PLUGIN_LOG_LEVEL");
714 if (log_level_str != NULL)
715 g_log_level = strtol(log_level_str, NULL, 10);
716}
717
718static const char* v4l_cmd2str(unsigned long int cmd)
719{
720 switch (cmd) {
721 case VIDIOC_QUERYCAP:
722 return "VIDIOC_QUERYCAP";
723 case VIDIOC_TRY_FMT:
724 return "VIDIOC_TRY_FMT";
725 case VIDIOC_S_FMT:
726 return "VIDIOC_S_FMT";
727 case VIDIOC_G_FMT:
728 return "VIDIOC_G_FMT";
729 case VIDIOC_ENUM_FMT:
730 return "VIDIOC_ENUM_FMT";
731 case VIDIOC_S_PARM:
732 return "VIDIOC_S_PARM";
733 case VIDIOC_G_PARM:
734 return "VIDIOC_G_PARM";
735 case VIDIOC_QBUF:
736 return "VIDIOC_QBUF";
737 case VIDIOC_DQBUF:
738 return "VIDIOC_DQBUF";
739 case VIDIOC_PREPARE_BUF:
740 return "VIDIOC_PREPARE_BUF";
741 case VIDIOC_CREATE_BUFS:
742 return "VIDIOC_CREATE_BUFS";
743 case VIDIOC_REQBUFS:
744 return "VIDIOC_REQBUFS";
745 case VIDIOC_STREAMON:
746 return "VIDIOC_STREAMON";
747 case VIDIOC_STREAMOFF:
748 return "VIDIOC_STREAMOFF";
749 case VIDIOC_S_CROP:
750 return "VIDIOC_S_CROP";
751 case VIDIOC_S_CTRL:
752 return "VIDIOC_S_CTRL";
753 case VIDIOC_G_EXT_CTRLS:
754 return "VIDIOC_G_EXT_CTRLS";
755 case VIDIOC_S_EXT_CTRLS:
756 return "VIDIOC_S_EXT_CTRLS";
757 case VIDIOC_QUERYBUF:
758 return "VIDIOC_QUERYBUF";
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900759 case VIDIOC_ENCODER_CMD:
760 return "VIDIOC_ENCODER_CMD";
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800761 default:
762 return "UNKNOWN";
763 }
henryhsu58be50c2014-10-30 11:49:19 +0800764}
765
766PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = {
767 .init = &plugin_init,
768 .close = &plugin_close,
769 .ioctl = &plugin_ioctl,
770};