blob: 7edda586cada847a99f04d0ad57196b9de372fdd [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"
Francois Buergisser79286ec2019-08-02 16:44:32 +090048#define HANTRO_VPU_NAME "hantro-vpu"
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080049#define DEFAULT_FRAME_RATE 30
50#define DEFAULT_BITRATE 1000000
henryhsuc7c06f92014-11-24 15:57:08 +080051#define PENDING_BUFFER_QUEUE_SIZE VIDEO_MAX_FRAME
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080052
henryhsuc7c06f92014-11-24 15:57:08 +080053/*
54 * struct pending_buffer - A v4l2 buffer pending for QBUF.
55 * @buffer: v4l2 buffer for QBUF.
56 * @planes: plane info of v4l2 buffer.
57 * @next_runtime_param: runtime parameters like framerate, bitrate, and
58 * keyframe for the next buffer.
59 */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080060struct pending_buffer {
61 struct v4l2_buffer buffer;
62 struct v4l2_plane planes[VIDEO_MAX_PLANES];
henryhsuc7c06f92014-11-24 15:57:08 +080063 struct rk_vepu_runtime_param next_runtime_param;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080064};
henryhsuc7c06f92014-11-24 15:57:08 +080065
66/*
67 * struct pending_buffer_queue - a ring buffer of pending buffers.
68 * @count: the number of buffers stored in the array.
69 * @front: the index of the first ready buffer.
70 * @buf_array: pending buffer array.
71 */
72struct pending_buffer_queue {
73 uint32_t count;
74 int32_t front;
75 struct pending_buffer buf_array[PENDING_BUFFER_QUEUE_SIZE];
76};
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080077
78/*
79 * struct encoder_context - the context of an encoder instance.
80 * @enc: Encoder instance returned from rk_vepu_create().
81 * @mutex: The mutex to protect encoder_context.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080082 * @output_streamon_type: Type of output interface when it streams on.
83 * @capture_streamon_type: Type of capture interface when it streams on.
henryhsuc7c06f92014-11-24 15:57:08 +080084 * @init_param: Encoding parameters like input format, resolution, and etc.
85 * These parameters will be passed to encoder at libvpu
86 * initialization.
87 * @runtime_param: Runtime parameters like framerate, bitrate, and
88 * keyframe. This is only used for receiving ext_ctrls
89 * before streamon and pending buffer queue is empty.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080090 * @pending_buffers: The pending v4l2 buffers waiting for the encoding
91 * configuration. After a previous buffer is dequeued,
92 * one buffer from the queue can be queued.
93 * @can_qbuf: Indicate that we can queue one source buffer. This is true only
94 * when the parameters to pass together with the source buffer are
95 * ready; those params are received on dequeing the previous
96 * destination buffer.
97 * @get_param_payload: Payload of V4L2_CID_PRIVATE_RK3288_GET_PARAMS. This is
98 * used to update the encoder configuration by
99 * rk_vepu_update_config().
100 * @get_param_payload_size: The size of get_param_payload.
101 * @v4l2_ctrls: v4l2 controls for VIDIOC_S_EXT_CTRLS.
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900102 * @flushing: Indicate the encoder is flushing frame.
103 * @eos_buffer: The last buffer to be flushed. Reset to NULL after the buffer
104 * is enqueued to the driver.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800105 */
106struct encoder_context {
107 void *enc;
108 pthread_mutex_t mutex;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800109 enum v4l2_buf_type output_streamon_type;
110 enum v4l2_buf_type capture_streamon_type;
henryhsuc7c06f92014-11-24 15:57:08 +0800111 struct rk_vepu_init_param init_param;
112 struct rk_vepu_runtime_param runtime_param;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800113 struct pending_buffer_queue pending_buffers;
114 bool can_qbuf;
115 void *get_param_payload;
116 size_t get_param_payload_size;
117 struct v4l2_ext_control v4l2_ctrls[MAX_NUM_GET_CONFIG_CTRLS];
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900118 bool flushing;
119 struct pending_buffer *eos_buffer;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800120};
121
122static void *plugin_init(int fd);
123static void plugin_close(void *dev_ops_priv);
124static int plugin_ioctl(void *dev_ops_priv, int fd, unsigned long int cmd,
125 void *arg);
126
127/* Functions to handle various ioctl. */
128static int ioctl_streamon_locked(
129 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
130static int ioctl_streamoff_locked(
131 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
132static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
133 struct v4l2_buffer *buffer);
134static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
135 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800136static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
137 struct v4l2_ext_controls *ext_ctrls);
138static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
139 struct v4l2_streamparm *parms);
140static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
141 struct v4l2_requestbuffers *reqbufs);
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900142static int ioctl_encoder_cmd_locked(struct encoder_context *ctx, int fd,
143 struct v4l2_encoder_cmd *argp);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800144
145/* Helper functions to manipulate the pending buffer queue. */
146
henryhsuc7c06f92014-11-24 15:57:08 +0800147static void queue_init(struct pending_buffer_queue *queue);
148static bool queue_empty(struct pending_buffer_queue *queue);
149static bool queue_full(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800150/* Insert a buffer to the tail of the queue. */
henryhsuc7c06f92014-11-24 15:57:08 +0800151static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800152 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800153/* Remove a buffer from the head of the queue. */
154static void queue_pop_front(struct pending_buffer_queue *queue);
155static struct pending_buffer *queue_front(struct pending_buffer_queue *queue);
156static struct pending_buffer *queue_back(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800157
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800158/* Returns true if the fd is Rockchip encoder device. */
159bool is_rockchip_encoder(int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800160/* Set encoder configuration to the driver. */
henryhsuc7c06f92014-11-24 15:57:08 +0800161int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Francois BUERGISSERaac7c202019-05-27 09:56:08 +0900162 size_t num_ctrls, uint32_t ctrls_ids[], void **payloads,
163 uint32_t payload_sizes[]);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800164/* QBUF a buffer from the pending buffer queue if it is not empty. */
henryhsuc7c06f92014-11-24 15:57:08 +0800165static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
166 int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800167/* Get the encoder parameters using G_FMT and initialize libvpu. */
168static int initialize_libvpu(struct encoder_context *ctx, int fd);
169/* Return the string represenation of a libv4l command for debugging. */
170static const char *v4l_cmd2str(unsigned long int cmd);
Alpha Linfa5caae2014-11-17 09:48:35 +0800171/* Get the log level from the environment variable LIBV4L_PLUGIN_LOG_LEVEL. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800172static void get_log_level();
173static pthread_once_t g_get_log_level_once = PTHREAD_ONCE_INIT;
174
henryhsu58be50c2014-10-30 11:49:19 +0800175static void *plugin_init(int fd)
176{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800177 int ret;
178 struct v4l2_query_ext_ctrl ext_ctrl;
179
180 pthread_once(&g_get_log_level_once, get_log_level);
181
182 VLOG_FD(1, "");
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800183 if (!is_rockchip_encoder(fd))
184 return NULL;
185
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800186 struct encoder_context *ctx = (struct encoder_context *)
187 calloc(1, sizeof(struct encoder_context));
188 if (ctx == NULL) {
189 errno = ENOMEM;
190 goto fail;
191 }
192 ret = pthread_mutex_init(&ctx->mutex, NULL);
193 if (ret)
194 goto fail;
henryhsuc7c06f92014-11-24 15:57:08 +0800195 queue_init(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800196
197 memset(&ext_ctrl, 0, sizeof(ext_ctrl));
198 ext_ctrl.id = V4L2_CID_PRIVATE_RK3288_GET_PARAMS;
199 ret = SYS_IOCTL(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl);
200 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800201 goto fail;
202 }
203 ctx->get_param_payload_size = ext_ctrl.elem_size;
204 ctx->get_param_payload = calloc(1, ctx->get_param_payload_size);
205 if (ctx->get_param_payload == NULL) {
206 errno = ENOMEM;
207 goto fail;
208 }
henryhsuc7c06f92014-11-24 15:57:08 +0800209 ctx->runtime_param.framerate_numer = DEFAULT_FRAME_RATE;
210 ctx->runtime_param.framerate_denom = 1;
211 ctx->runtime_param.bitrate = DEFAULT_BITRATE;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800212 VLOG_FD(1, "Success. ctx=%p", ctx);
213 return ctx;
214
215fail:
216 plugin_close(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800217 return NULL;
218}
219
220static void plugin_close(void *dev_ops_priv)
221{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800222 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
223
224 VLOG(1, "ctx=%p", ctx);
225 if (ctx == NULL)
226 return;
227
228 pthread_mutex_lock(&ctx->mutex);
229 if (ctx->enc)
230 rk_vepu_deinit(ctx->enc);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800231 free(ctx->get_param_payload);
232 ctx->get_param_payload = NULL;
233 pthread_mutex_unlock(&ctx->mutex);
234 pthread_mutex_destroy(&ctx->mutex);
235
236 free(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800237}
238
239static int plugin_ioctl(void *dev_ops_priv, int fd,
240 unsigned long int cmd, void *arg)
241{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800242 int ret;
243 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
244
245 VLOG_FD(1, "%s(%lu)", v4l_cmd2str(cmd), _IOC_NR(cmd));
246
247 pthread_mutex_lock(&ctx->mutex);
248 switch (cmd) {
249 case VIDIOC_STREAMON:
henryhsuc7c06f92014-11-24 15:57:08 +0800250 ret = ioctl_streamon_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800251 break;
252
253 case VIDIOC_STREAMOFF:
henryhsuc7c06f92014-11-24 15:57:08 +0800254 ret = ioctl_streamoff_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800255 break;
256
257 case VIDIOC_QBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800258 ret = ioctl_qbuf_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800259 break;
260
261 case VIDIOC_DQBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800262 ret = ioctl_dqbuf_locked(ctx, fd, arg);
263 break;
264
265 case VIDIOC_S_EXT_CTRLS:
266 ret = ioctl_s_ext_ctrls_locked(ctx, fd, arg);
267 break;
268
269 case VIDIOC_S_PARM:
270 ret = ioctl_s_parm_locked(ctx, fd, arg);
271 break;
272
273 case VIDIOC_REQBUFS:
274 ret = ioctl_reqbufs_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800275 break;
276
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900277 case VIDIOC_ENCODER_CMD:
278 ret = ioctl_encoder_cmd_locked(ctx, fd, arg);
279 break;
280
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800281 default:
282 ret = SYS_IOCTL(fd, cmd, arg);
283 break;
284 }
285 pthread_mutex_unlock(&ctx->mutex);
286 return ret;
287}
288
289static int ioctl_streamon_locked(
290 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
291{
292 int ret = SYS_IOCTL(fd, VIDIOC_STREAMON, type);
293 if (ret)
294 return ret;
295
296 if (V4L2_TYPE_IS_OUTPUT(*type))
297 ctx->output_streamon_type = *type;
298 else
299 ctx->capture_streamon_type = *type;
300 if (ctx->output_streamon_type && ctx->capture_streamon_type) {
301 ret = initialize_libvpu(ctx, fd);
302 if (ret)
303 return ret;
304 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800305 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800306 }
307 return 0;
308}
309
310static int ioctl_streamoff_locked(
311 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
312{
313 int ret = SYS_IOCTL(fd, VIDIOC_STREAMOFF, type);
314 if (ret)
315 return ret;
316
317 if (V4L2_TYPE_IS_OUTPUT(*type))
318 ctx->output_streamon_type = 0;
319 else
320 ctx->capture_streamon_type = 0;
321 return 0;
322}
323
324static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
325 struct v4l2_buffer *buffer)
326{
327 size_t num_ctrls = 0;
328 uint32_t *ctrl_ids = NULL, *payload_sizes = NULL;
329 void **payloads = NULL;
330 int ret;
331
332 if (!V4L2_TYPE_IS_OUTPUT(buffer->type)) {
333 return SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
334 }
335
336 if (!ctx->can_qbuf) {
337 VLOG_FD(1, "Put buffer (%d) in the pending queue.",
338 buffer->index);
339 /*
340 * The last frame is not encoded yet. Put the buffer to the
341 * pending queue.
342 */
henryhsuc7c06f92014-11-24 15:57:08 +0800343 return queue_push_back(&ctx->pending_buffers, buffer);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800344 }
345 /* Get the encoder configuration from the library. */
346 if (rk_vepu_get_config(ctx->enc, &num_ctrls, &ctrl_ids, &payloads,
347 &payload_sizes)) {
348 VLOG_FD(0, "rk_vepu_get_config failed");
349 return -EIO;
350 }
351 /* Set the encoder configuration to the driver. */
Francois BUERGISSERaac7c202019-05-27 09:56:08 +0900352 ret = set_encoder_config_locked(ctx, fd, num_ctrls, ctrl_ids, payloads,
353 payload_sizes);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800354 if (ret)
355 return ret;
356
357 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));
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900393 ext_ctrls.count = 1;
394 ext_ctrls.controls = &v4l2_ctrl;
395 ret = SYS_IOCTL(fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls);
396 if (ret)
397 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800398
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900399 if (rk_vepu_update_config(ctx->enc, v4l2_ctrl.ptr,
400 v4l2_ctrl.size, bytesused)) {
401 VLOG_FD(0, "rk_vepu_update_config failed.");
402 return -EIO;
403 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800404 }
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900405
406 /* When flushing buffer, we don't queue any new buffer.
407 * So we ignore checking can_qbuf and trying to qbuf new buffer. */
408 assert(ctx->flushing || !ctx->can_qbuf);
409 if (buffer->flags & V4L2_BUF_FLAG_LAST)
410 ctx->flushing = false;
411 if (ctx->flushing)
412 return 0;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800413 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800414 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800415}
416
henryhsuc7c06f92014-11-24 15:57:08 +0800417static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
418 struct v4l2_ext_controls *ext_ctrls)
419{
420 size_t i;
421 struct rk_vepu_runtime_param *runtime_param_ptr;
422
423 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
424 /*
425 * If buffer queue is empty, update parameters directly.
426 * If buffer queue is not empty, save parameters to the last buffer. And
427 * these values will be sent again when the buffer is ready to deliver.
428 */
429 if (!no_pending_buffer) {
430 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
431 runtime_param_ptr = &element->next_runtime_param;
432 } else {
433 runtime_param_ptr = &ctx->runtime_param;
434 }
435
436 /*
437 * Check each extension control to update keyframe and bitrate
438 * parameters.
439 */
440 for (i = 0; i < ext_ctrls->count; i++) {
441 switch (ext_ctrls->controls[i].id) {
Heng-Ruey Hsu61eb2ec2016-05-20 18:11:53 +0800442 case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
443 runtime_param_ptr->keyframe_request = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800444 break;
445 case V4L2_CID_MPEG_VIDEO_BITRATE:
446 runtime_param_ptr->bitrate = ext_ctrls->controls[i].value;
447 break;
448 default:
449 break;
450 }
451 }
452
453 if (no_pending_buffer && ctx->enc) {
454 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
455 VLOG_FD(0, "rk_vepu_update_parameter failed.");
456 return -EIO;
457 }
458 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
459 }
460 /* Driver should ignore keyframe and bitrate controls */
461 return SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, ext_ctrls);
462}
463
464static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
465 struct v4l2_streamparm *parms)
466{
467 if (V4L2_TYPE_IS_OUTPUT(parms->type)
468 && parms->parm.output.timeperframe.denominator) {
469 struct rk_vepu_runtime_param *runtime_param_ptr;
470 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
471 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
472
473 runtime_param_ptr = no_pending_buffer ? &ctx->runtime_param :
474 &element->next_runtime_param;
475 runtime_param_ptr->framerate_numer =
476 parms->parm.output.timeperframe.denominator;
477 runtime_param_ptr->framerate_denom =
478 parms->parm.output.timeperframe.numerator;
479
480 if (!no_pending_buffer || !ctx->enc)
481 return 0;
482 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
483 VLOG_FD(0, "rk_vepu_update_parameter failed.");
484 return -EIO;
485 }
486 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
487 return 0;
488 }
489 return SYS_IOCTL(fd, VIDIOC_S_PARM, parms);
490}
491
492static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
493 struct v4l2_requestbuffers *reqbufs)
494{
495 int ret = SYS_IOCTL(fd, VIDIOC_REQBUFS, reqbufs);
496 if (ret)
497 return ret;
498 queue_init(&ctx->pending_buffers);
499 return 0;
500}
501
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900502static int ioctl_encoder_cmd_locked(struct encoder_context *ctx, int fd,
503 struct v4l2_encoder_cmd *argp)
504{
505 if (argp->cmd == V4L2_ENC_CMD_STOP) {
506 if (ctx->flushing) {
507 VLOG_FD(0, "previous stop command is not handled yet.");
508 return -EINVAL;
509 }
510 ctx->flushing = true;
511 /* If there is any pending buffer, then send the stop command
512 * after we enqueue the last buffer. Otherwise, we just send
513 * the command to the kernel instantly. */
514 if (!queue_empty(&ctx->pending_buffers)) {
515 ctx->eos_buffer = queue_back(&ctx->pending_buffers);
516 return 0;
517 }
518 }
519 return SYS_IOCTL(fd, VIDIOC_ENCODER_CMD, argp);
520}
521
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800522bool is_rockchip_encoder(int fd) {
523 struct v4l2_capability cap;
524 memset(&cap, 0, sizeof(cap));
525 int ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
526 if (ret)
527 return false;
Francois Buergisser79286ec2019-08-02 16:44:32 +0900528
529 return strcmp(RK3288_VPU_NAME, (const char *)cap.driver) == 0 ||
530 strcmp(HANTRO_VPU_NAME, (const char *)cap.driver) == 0;
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800531}
532
henryhsuc7c06f92014-11-24 15:57:08 +0800533int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Francois BUERGISSERaac7c202019-05-27 09:56:08 +0900534 size_t num_ctrls, uint32_t ctrl_ids[], void **payloads,
535 uint32_t payload_sizes[])
henryhsuc7c06f92014-11-24 15:57:08 +0800536{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800537 size_t i;
538 struct v4l2_ext_controls ext_ctrls;
539
540 if (num_ctrls <= 0)
541 return 0;
542
543 assert(num_ctrls <= MAX_NUM_GET_CONFIG_CTRLS);
henryhsuc7c06f92014-11-24 15:57:08 +0800544 if (num_ctrls > MAX_NUM_GET_CONFIG_CTRLS) {
545 VLOG_FD(0, "The number of controls exceeds limit.");
546 return -EIO;
547 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800548 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800549 ext_ctrls.count = num_ctrls;
550 ext_ctrls.controls = ctx->v4l2_ctrls;
551 memset(ctx->v4l2_ctrls, 0, sizeof(ctx->v4l2_ctrls));
552 for (i = 0; i < num_ctrls; ++i) {
553 ctx->v4l2_ctrls[i].id = ctrl_ids[i];
554 ctx->v4l2_ctrls[i].ptr = payloads[i];
555 ctx->v4l2_ctrls[i].size = payload_sizes[i];
556 }
557 int ret = SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, &ext_ctrls);
558 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800559 return ret;
560 }
561 return 0;
562}
563
henryhsuc7c06f92014-11-24 15:57:08 +0800564static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
565 int fd)
566{
567 if (!queue_empty(&ctx->pending_buffers)) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800568 int ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800569 struct pending_buffer *element = queue_front(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800570 VLOG_FD(1, "QBUF a buffer (%d) from the pending queue.",
571 element->buffer.index);
henryhsuc7c06f92014-11-24 15:57:08 +0800572 if (rk_vepu_update_parameter(ctx->enc, &element->next_runtime_param)) {
573 VLOG_FD(0, "rk_vepu_update_parameter failed.");
574 return -EIO;
575 }
Tomasz Figaaed2ed92015-02-25 14:05:53 +0900576 memset(&element->next_runtime_param, 0,
577 sizeof(element->next_runtime_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800578 ret = ioctl_qbuf_locked(ctx, fd, &element->buffer);
579 if (ret)
580 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800581 queue_pop_front(&ctx->pending_buffers);
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900582 /* QBUF the last buffer to be flushed, send stop command. */
583 if (element == ctx->eos_buffer) {
584 ctx->eos_buffer = NULL;
585 struct v4l2_encoder_cmd argp = {
586 .cmd = V4L2_ENC_CMD_STOP,
587 };
588 return SYS_IOCTL(fd, VIDIOC_ENCODER_CMD, &argp);
589 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800590 }
591 return 0;
592}
593
henryhsuc7c06f92014-11-24 15:57:08 +0800594static int initialize_libvpu(struct encoder_context *ctx, int fd)
595{
596 struct rk_vepu_init_param init_param;
597 memset(&init_param, 0, sizeof(init_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800598
Alpha Linfa5caae2014-11-17 09:48:35 +0800599 /* Get the input format. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800600 struct v4l2_format format;
601 memset(&format, 0, sizeof(format));
602 format.type = ctx->output_streamon_type;
603 int ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
Alpha Linfa5caae2014-11-17 09:48:35 +0800604 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800605 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800606 init_param.input_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800607
Alpha Linfa5caae2014-11-17 09:48:35 +0800608 /* Get the output format. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800609 memset(&format, 0, sizeof(format));
610 format.type = ctx->capture_streamon_type;
611 ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
Alpha Linfa5caae2014-11-17 09:48:35 +0800612 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800613 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800614 init_param.output_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800615
Alpha Linfa5caae2014-11-17 09:48:35 +0800616 /* Get the cropped size. */
617 struct v4l2_crop crop;
618 memset(&crop, 0, sizeof(crop));
619 crop.type = ctx->output_streamon_type;
620 ret = SYS_IOCTL(fd, VIDIOC_G_CROP, &crop);
621 if (ret)
622 return ret;
623 init_param.width = crop.c.width;
624 init_param.height = crop.c.height;
625
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800626 /*
627 * If the encoder library has initialized and parameters have not
628 * changed, skip the initialization.
629 */
henryhsuc7c06f92014-11-24 15:57:08 +0800630 if (ctx->enc && memcmp(&init_param, &ctx->init_param, sizeof(init_param))) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800631 rk_vepu_deinit(ctx->enc);
henryhsuc7c06f92014-11-24 15:57:08 +0800632 ctx->enc = NULL;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800633 }
henryhsuc7c06f92014-11-24 15:57:08 +0800634 if (!ctx->enc) {
635 memcpy(&ctx->init_param, &init_param, sizeof(init_param));
636 ctx->enc = rk_vepu_init(&init_param);
637 if (ctx->enc == NULL) {
638 VLOG_FD(0, "Failed to initialize encoder library.");
639 return -EIO;
640 }
641 }
642 if (rk_vepu_update_parameter(ctx->enc, &ctx->runtime_param)) {
643 VLOG_FD(0, "rk_vepu_update_parameter failed.");
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800644 return -EIO;
645 }
henryhsuc7c06f92014-11-24 15:57:08 +0800646 memset(&ctx->runtime_param, 0, sizeof(struct rk_vepu_runtime_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800647 return 0;
648}
649
henryhsuc7c06f92014-11-24 15:57:08 +0800650static void queue_init(struct pending_buffer_queue *queue)
651{
652 memset(queue, 0, sizeof(struct pending_buffer_queue));
653}
654
655static bool queue_empty(struct pending_buffer_queue *queue)
656{
657 return queue->count == 0;
658}
659
660static bool queue_full(struct pending_buffer_queue *queue)
661{
662 return queue->count == PENDING_BUFFER_QUEUE_SIZE;
663}
664
665static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800666 struct v4l2_buffer *buffer)
667{
henryhsuc7c06f92014-11-24 15:57:08 +0800668 if (queue_full(queue))
669 return -ENOMEM;
670 int rear = (queue->front + queue->count) % PENDING_BUFFER_QUEUE_SIZE;
671 queue->count++;
672 struct pending_buffer *entry = &queue->buf_array[rear];
673 memset(entry, 0, sizeof(struct pending_buffer));
674
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800675 memcpy(&entry->buffer, buffer, sizeof(*buffer));
676 if (V4L2_TYPE_IS_MULTIPLANAR(buffer->type)) {
677 memset(entry->planes, 0,
678 sizeof(struct v4l2_plane) * VIDEO_MAX_PLANES);
679 memcpy(entry->planes, buffer->m.planes,
680 sizeof(struct v4l2_plane) * buffer->length);
681 entry->buffer.m.planes = entry->planes;
682 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800683 return 0;
684}
685
henryhsuc7c06f92014-11-24 15:57:08 +0800686static void queue_pop_front(struct pending_buffer_queue *queue)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800687{
henryhsuc7c06f92014-11-24 15:57:08 +0800688 assert(!queue_empty(queue));
689 queue->count--;
690 queue->front = (queue->front + 1) % PENDING_BUFFER_QUEUE_SIZE;
691}
692
693static struct pending_buffer *queue_front(struct pending_buffer_queue *queue)
694{
695 if (queue_empty(queue))
696 return NULL;
697 return &queue->buf_array[queue->front];
698}
699
700static struct pending_buffer *queue_back(struct pending_buffer_queue *queue)
701{
702 if (queue_empty(queue))
703 return NULL;
704 return &queue->buf_array[(queue->front + queue->count - 1) %
705 PENDING_BUFFER_QUEUE_SIZE];
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800706}
707
708static void get_log_level()
709{
710 char *log_level_str = getenv("LIBV4L_PLUGIN_LOG_LEVEL");
711 if (log_level_str != NULL)
712 g_log_level = strtol(log_level_str, NULL, 10);
713}
714
715static const char* v4l_cmd2str(unsigned long int cmd)
716{
717 switch (cmd) {
718 case VIDIOC_QUERYCAP:
719 return "VIDIOC_QUERYCAP";
720 case VIDIOC_TRY_FMT:
721 return "VIDIOC_TRY_FMT";
722 case VIDIOC_S_FMT:
723 return "VIDIOC_S_FMT";
724 case VIDIOC_G_FMT:
725 return "VIDIOC_G_FMT";
726 case VIDIOC_ENUM_FMT:
727 return "VIDIOC_ENUM_FMT";
728 case VIDIOC_S_PARM:
729 return "VIDIOC_S_PARM";
730 case VIDIOC_G_PARM:
731 return "VIDIOC_G_PARM";
732 case VIDIOC_QBUF:
733 return "VIDIOC_QBUF";
734 case VIDIOC_DQBUF:
735 return "VIDIOC_DQBUF";
736 case VIDIOC_PREPARE_BUF:
737 return "VIDIOC_PREPARE_BUF";
738 case VIDIOC_CREATE_BUFS:
739 return "VIDIOC_CREATE_BUFS";
740 case VIDIOC_REQBUFS:
741 return "VIDIOC_REQBUFS";
742 case VIDIOC_STREAMON:
743 return "VIDIOC_STREAMON";
744 case VIDIOC_STREAMOFF:
745 return "VIDIOC_STREAMOFF";
746 case VIDIOC_S_CROP:
747 return "VIDIOC_S_CROP";
748 case VIDIOC_S_CTRL:
749 return "VIDIOC_S_CTRL";
750 case VIDIOC_G_EXT_CTRLS:
751 return "VIDIOC_G_EXT_CTRLS";
752 case VIDIOC_S_EXT_CTRLS:
753 return "VIDIOC_S_EXT_CTRLS";
754 case VIDIOC_QUERYBUF:
755 return "VIDIOC_QUERYBUF";
Chih-Yu Huang7762c812018-02-28 11:10:59 +0900756 case VIDIOC_ENCODER_CMD:
757 return "VIDIOC_ENCODER_CMD";
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800758 default:
759 return "UNKNOWN";
760 }
henryhsu58be50c2014-10-30 11:49:19 +0800761}
762
763PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = {
764 .init = &plugin_init,
765 .close = &plugin_close,
766 .ioctl = &plugin_ioctl,
767};