blob: 4767233d126ba33819cf093e332c0412d6ad1248 [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.
101 */
102struct encoder_context {
103 void *enc;
104 pthread_mutex_t mutex;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800105 enum v4l2_buf_type output_streamon_type;
106 enum v4l2_buf_type capture_streamon_type;
henryhsuc7c06f92014-11-24 15:57:08 +0800107 struct rk_vepu_init_param init_param;
108 struct rk_vepu_runtime_param runtime_param;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800109 struct pending_buffer_queue pending_buffers;
110 bool can_qbuf;
111 void *get_param_payload;
112 size_t get_param_payload_size;
113 struct v4l2_ext_control v4l2_ctrls[MAX_NUM_GET_CONFIG_CTRLS];
114};
115
116static void *plugin_init(int fd);
117static void plugin_close(void *dev_ops_priv);
118static int plugin_ioctl(void *dev_ops_priv, int fd, unsigned long int cmd,
119 void *arg);
120
121/* Functions to handle various ioctl. */
122static int ioctl_streamon_locked(
123 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
124static int ioctl_streamoff_locked(
125 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
126static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
127 struct v4l2_buffer *buffer);
128static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
129 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800130static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
131 struct v4l2_ext_controls *ext_ctrls);
132static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
133 struct v4l2_streamparm *parms);
134static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
135 struct v4l2_requestbuffers *reqbufs);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800136
137/* Helper functions to manipulate the pending buffer queue. */
138
henryhsuc7c06f92014-11-24 15:57:08 +0800139static void queue_init(struct pending_buffer_queue *queue);
140static bool queue_empty(struct pending_buffer_queue *queue);
141static bool queue_full(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800142/* Insert a buffer to the tail of the queue. */
henryhsuc7c06f92014-11-24 15:57:08 +0800143static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800144 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800145/* Remove a buffer from the head of the queue. */
146static void queue_pop_front(struct pending_buffer_queue *queue);
147static struct pending_buffer *queue_front(struct pending_buffer_queue *queue);
148static struct pending_buffer *queue_back(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800149
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800150/* Returns true if the fd is Rockchip encoder device. */
151bool is_rockchip_encoder(int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800152/* Set encoder configuration to the driver. */
henryhsuc7c06f92014-11-24 15:57:08 +0800153int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800154 uint32_t buffer_index, size_t num_ctrls, uint32_t ctrls_ids[],
155 void **payloads, uint32_t payload_sizes[]);
156/* QBUF a buffer from the pending buffer queue if it is not empty. */
henryhsuc7c06f92014-11-24 15:57:08 +0800157static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
158 int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800159/* Get the encoder parameters using G_FMT and initialize libvpu. */
160static int initialize_libvpu(struct encoder_context *ctx, int fd);
161/* Return the string represenation of a libv4l command for debugging. */
162static const char *v4l_cmd2str(unsigned long int cmd);
Alpha Linfa5caae2014-11-17 09:48:35 +0800163/* Get the log level from the environment variable LIBV4L_PLUGIN_LOG_LEVEL. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800164static void get_log_level();
165static pthread_once_t g_get_log_level_once = PTHREAD_ONCE_INIT;
166
henryhsu58be50c2014-10-30 11:49:19 +0800167static void *plugin_init(int fd)
168{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800169 int ret;
170 struct v4l2_query_ext_ctrl ext_ctrl;
171
172 pthread_once(&g_get_log_level_once, get_log_level);
173
174 VLOG_FD(1, "");
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800175 if (!is_rockchip_encoder(fd))
176 return NULL;
177
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800178 struct encoder_context *ctx = (struct encoder_context *)
179 calloc(1, sizeof(struct encoder_context));
180 if (ctx == NULL) {
181 errno = ENOMEM;
182 goto fail;
183 }
184 ret = pthread_mutex_init(&ctx->mutex, NULL);
185 if (ret)
186 goto fail;
henryhsuc7c06f92014-11-24 15:57:08 +0800187 queue_init(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800188
189 memset(&ext_ctrl, 0, sizeof(ext_ctrl));
190 ext_ctrl.id = V4L2_CID_PRIVATE_RK3288_GET_PARAMS;
191 ret = SYS_IOCTL(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl);
192 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800193 goto fail;
194 }
195 ctx->get_param_payload_size = ext_ctrl.elem_size;
196 ctx->get_param_payload = calloc(1, ctx->get_param_payload_size);
197 if (ctx->get_param_payload == NULL) {
198 errno = ENOMEM;
199 goto fail;
200 }
henryhsuc7c06f92014-11-24 15:57:08 +0800201 ctx->runtime_param.framerate_numer = DEFAULT_FRAME_RATE;
202 ctx->runtime_param.framerate_denom = 1;
203 ctx->runtime_param.bitrate = DEFAULT_BITRATE;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800204 VLOG_FD(1, "Success. ctx=%p", ctx);
205 return ctx;
206
207fail:
208 plugin_close(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800209 return NULL;
210}
211
212static void plugin_close(void *dev_ops_priv)
213{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800214 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
215
216 VLOG(1, "ctx=%p", ctx);
217 if (ctx == NULL)
218 return;
219
220 pthread_mutex_lock(&ctx->mutex);
221 if (ctx->enc)
222 rk_vepu_deinit(ctx->enc);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800223 free(ctx->get_param_payload);
224 ctx->get_param_payload = NULL;
225 pthread_mutex_unlock(&ctx->mutex);
226 pthread_mutex_destroy(&ctx->mutex);
227
228 free(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800229}
230
231static int plugin_ioctl(void *dev_ops_priv, int fd,
232 unsigned long int cmd, void *arg)
233{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800234 int ret;
235 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
236
237 VLOG_FD(1, "%s(%lu)", v4l_cmd2str(cmd), _IOC_NR(cmd));
238
239 pthread_mutex_lock(&ctx->mutex);
240 switch (cmd) {
241 case VIDIOC_STREAMON:
henryhsuc7c06f92014-11-24 15:57:08 +0800242 ret = ioctl_streamon_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800243 break;
244
245 case VIDIOC_STREAMOFF:
henryhsuc7c06f92014-11-24 15:57:08 +0800246 ret = ioctl_streamoff_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800247 break;
248
249 case VIDIOC_QBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800250 ret = ioctl_qbuf_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800251 break;
252
253 case VIDIOC_DQBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800254 ret = ioctl_dqbuf_locked(ctx, fd, arg);
255 break;
256
257 case VIDIOC_S_EXT_CTRLS:
258 ret = ioctl_s_ext_ctrls_locked(ctx, fd, arg);
259 break;
260
261 case VIDIOC_S_PARM:
262 ret = ioctl_s_parm_locked(ctx, fd, arg);
263 break;
264
265 case VIDIOC_REQBUFS:
266 ret = ioctl_reqbufs_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800267 break;
268
269 default:
270 ret = SYS_IOCTL(fd, cmd, arg);
271 break;
272 }
273 pthread_mutex_unlock(&ctx->mutex);
274 return ret;
275}
276
277static int ioctl_streamon_locked(
278 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
279{
280 int ret = SYS_IOCTL(fd, VIDIOC_STREAMON, type);
281 if (ret)
282 return ret;
283
284 if (V4L2_TYPE_IS_OUTPUT(*type))
285 ctx->output_streamon_type = *type;
286 else
287 ctx->capture_streamon_type = *type;
288 if (ctx->output_streamon_type && ctx->capture_streamon_type) {
289 ret = initialize_libvpu(ctx, fd);
290 if (ret)
291 return ret;
292 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800293 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800294 }
295 return 0;
296}
297
298static int ioctl_streamoff_locked(
299 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
300{
301 int ret = SYS_IOCTL(fd, VIDIOC_STREAMOFF, type);
302 if (ret)
303 return ret;
304
305 if (V4L2_TYPE_IS_OUTPUT(*type))
306 ctx->output_streamon_type = 0;
307 else
308 ctx->capture_streamon_type = 0;
309 return 0;
310}
311
312static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
313 struct v4l2_buffer *buffer)
314{
315 size_t num_ctrls = 0;
316 uint32_t *ctrl_ids = NULL, *payload_sizes = NULL;
317 void **payloads = NULL;
318 int ret;
319
320 if (!V4L2_TYPE_IS_OUTPUT(buffer->type)) {
321 return SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
322 }
323
324 if (!ctx->can_qbuf) {
325 VLOG_FD(1, "Put buffer (%d) in the pending queue.",
326 buffer->index);
327 /*
328 * The last frame is not encoded yet. Put the buffer to the
329 * pending queue.
330 */
henryhsuc7c06f92014-11-24 15:57:08 +0800331 return queue_push_back(&ctx->pending_buffers, buffer);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800332 }
333 /* Get the encoder configuration from the library. */
334 if (rk_vepu_get_config(ctx->enc, &num_ctrls, &ctrl_ids, &payloads,
335 &payload_sizes)) {
336 VLOG_FD(0, "rk_vepu_get_config failed");
337 return -EIO;
338 }
339 /* Set the encoder configuration to the driver. */
henryhsuc7c06f92014-11-24 15:57:08 +0800340 ret = set_encoder_config_locked(ctx, fd, buffer->index, num_ctrls, ctrl_ids,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800341 payloads, payload_sizes);
342 if (ret)
343 return ret;
344
Heng-Ruey Hsu61eb2ec2016-05-20 18:11:53 +0800345 buffer->config_store = buffer->index + 1;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800346 ret = SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
347 if (ret == 0)
348 ctx->can_qbuf = false;
349 else
350 VLOG(0, "QBUF failed. errno=%d", errno);
351 return ret;
352}
353
354static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
355 struct v4l2_buffer *buffer)
356{
357 struct v4l2_ext_controls ext_ctrls;
358 struct v4l2_ext_control v4l2_ctrl;
359 int ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800360 uint32_t bytesused;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800361
362 if (V4L2_TYPE_IS_OUTPUT(buffer->type)) {
363 return SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
364 }
365
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800366 ret = SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
367 if (ret)
368 return ret;
369
Wu-Cheng Lif1e616b2014-11-21 15:11:34 +0800370 assert(!ctx->can_qbuf);
371
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800372 /* Get the encoder configuration and update the library. */
373 memset(ctx->get_param_payload, 0, ctx->get_param_payload_size);
374 memset(&v4l2_ctrl, 0, sizeof(v4l2_ctrl));
375 v4l2_ctrl.id = V4L2_CID_PRIVATE_RK3288_GET_PARAMS;
376 v4l2_ctrl.size = ctx->get_param_payload_size;
Wu-Cheng Liadc8ec82014-11-21 15:51:59 +0800377 v4l2_ctrl.ptr = ctx->get_param_payload;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800378 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
379 /* TODO: change this to config_store after the header is updated. */
henryhsuc7c06f92014-11-24 15:57:08 +0800380 ext_ctrls.ctrl_class = 0;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800381 ext_ctrls.count = 1;
382 ext_ctrls.controls = &v4l2_ctrl;
383 ret = SYS_IOCTL(fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls);
henryhsuc7c06f92014-11-24 15:57:08 +0800384 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800385 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800386 bytesused = V4L2_TYPE_IS_MULTIPLANAR(buffer->type) ?
387 buffer->m.planes[0].bytesused : buffer->bytesused;
388
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800389 if (rk_vepu_update_config(ctx->enc, v4l2_ctrl.ptr, v4l2_ctrl.size,
henryhsuc7c06f92014-11-24 15:57:08 +0800390 bytesused)) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800391 VLOG_FD(0, "rk_vepu_update_config failed.");
392 return -EIO;
393 }
394 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800395 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800396}
397
henryhsuc7c06f92014-11-24 15:57:08 +0800398static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
399 struct v4l2_ext_controls *ext_ctrls)
400{
401 size_t i;
402 struct rk_vepu_runtime_param *runtime_param_ptr;
403
404 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
405 /*
406 * If buffer queue is empty, update parameters directly.
407 * If buffer queue is not empty, save parameters to the last buffer. And
408 * these values will be sent again when the buffer is ready to deliver.
409 */
410 if (!no_pending_buffer) {
411 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
412 runtime_param_ptr = &element->next_runtime_param;
413 } else {
414 runtime_param_ptr = &ctx->runtime_param;
415 }
416
417 /*
418 * Check each extension control to update keyframe and bitrate
419 * parameters.
420 */
421 for (i = 0; i < ext_ctrls->count; i++) {
422 switch (ext_ctrls->controls[i].id) {
Heng-Ruey Hsu61eb2ec2016-05-20 18:11:53 +0800423 case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
424 runtime_param_ptr->keyframe_request = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800425 break;
426 case V4L2_CID_MPEG_VIDEO_BITRATE:
427 runtime_param_ptr->bitrate = ext_ctrls->controls[i].value;
428 break;
429 default:
430 break;
431 }
432 }
433
434 if (no_pending_buffer && ctx->enc) {
435 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
436 VLOG_FD(0, "rk_vepu_update_parameter failed.");
437 return -EIO;
438 }
439 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
440 }
441 /* Driver should ignore keyframe and bitrate controls */
442 return SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, ext_ctrls);
443}
444
445static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
446 struct v4l2_streamparm *parms)
447{
448 if (V4L2_TYPE_IS_OUTPUT(parms->type)
449 && parms->parm.output.timeperframe.denominator) {
450 struct rk_vepu_runtime_param *runtime_param_ptr;
451 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
452 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
453
454 runtime_param_ptr = no_pending_buffer ? &ctx->runtime_param :
455 &element->next_runtime_param;
456 runtime_param_ptr->framerate_numer =
457 parms->parm.output.timeperframe.denominator;
458 runtime_param_ptr->framerate_denom =
459 parms->parm.output.timeperframe.numerator;
460
461 if (!no_pending_buffer || !ctx->enc)
462 return 0;
463 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
464 VLOG_FD(0, "rk_vepu_update_parameter failed.");
465 return -EIO;
466 }
467 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
468 return 0;
469 }
470 return SYS_IOCTL(fd, VIDIOC_S_PARM, parms);
471}
472
473static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
474 struct v4l2_requestbuffers *reqbufs)
475{
476 int ret = SYS_IOCTL(fd, VIDIOC_REQBUFS, reqbufs);
477 if (ret)
478 return ret;
479 queue_init(&ctx->pending_buffers);
480 return 0;
481}
482
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800483bool is_rockchip_encoder(int fd) {
484 struct v4l2_capability cap;
485 memset(&cap, 0, sizeof(cap));
486 int ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
487 if (ret)
488 return false;
Alpha Linfa5caae2014-11-17 09:48:35 +0800489 return strcmp(RK3288_VPU_NAME, (const char *)cap.driver) == 0;
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800490}
491
henryhsuc7c06f92014-11-24 15:57:08 +0800492int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800493 uint32_t buffer_index, size_t num_ctrls, uint32_t ctrl_ids[],
henryhsuc7c06f92014-11-24 15:57:08 +0800494 void **payloads, uint32_t payload_sizes[])
495{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800496 size_t i;
497 struct v4l2_ext_controls ext_ctrls;
498
499 if (num_ctrls <= 0)
500 return 0;
501
502 assert(num_ctrls <= MAX_NUM_GET_CONFIG_CTRLS);
henryhsuc7c06f92014-11-24 15:57:08 +0800503 if (num_ctrls > MAX_NUM_GET_CONFIG_CTRLS) {
504 VLOG_FD(0, "The number of controls exceeds limit.");
505 return -EIO;
506 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800507 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
508 /* TODO: change this to config_store after the header is updated. */
509 ext_ctrls.ctrl_class = buffer_index + 1;
510 ext_ctrls.count = num_ctrls;
511 ext_ctrls.controls = ctx->v4l2_ctrls;
512 memset(ctx->v4l2_ctrls, 0, sizeof(ctx->v4l2_ctrls));
513 for (i = 0; i < num_ctrls; ++i) {
514 ctx->v4l2_ctrls[i].id = ctrl_ids[i];
515 ctx->v4l2_ctrls[i].ptr = payloads[i];
516 ctx->v4l2_ctrls[i].size = payload_sizes[i];
517 }
518 int ret = SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, &ext_ctrls);
519 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800520 return ret;
521 }
522 return 0;
523}
524
henryhsuc7c06f92014-11-24 15:57:08 +0800525static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
526 int fd)
527{
528 if (!queue_empty(&ctx->pending_buffers)) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800529 int ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800530 struct pending_buffer *element = queue_front(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800531 VLOG_FD(1, "QBUF a buffer (%d) from the pending queue.",
532 element->buffer.index);
henryhsuc7c06f92014-11-24 15:57:08 +0800533 if (rk_vepu_update_parameter(ctx->enc, &element->next_runtime_param)) {
534 VLOG_FD(0, "rk_vepu_update_parameter failed.");
535 return -EIO;
536 }
Tomasz Figaaed2ed92015-02-25 14:05:53 +0900537 memset(&element->next_runtime_param, 0,
538 sizeof(element->next_runtime_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800539 ret = ioctl_qbuf_locked(ctx, fd, &element->buffer);
540 if (ret)
541 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800542 queue_pop_front(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800543 }
544 return 0;
545}
546
henryhsuc7c06f92014-11-24 15:57:08 +0800547static int initialize_libvpu(struct encoder_context *ctx, int fd)
548{
549 struct rk_vepu_init_param init_param;
550 memset(&init_param, 0, sizeof(init_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800551
Alpha Linfa5caae2014-11-17 09:48:35 +0800552 /* Get the input format. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800553 struct v4l2_format format;
554 memset(&format, 0, sizeof(format));
555 format.type = ctx->output_streamon_type;
556 int ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
Alpha Linfa5caae2014-11-17 09:48:35 +0800557 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800558 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800559 init_param.input_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800560
Alpha Linfa5caae2014-11-17 09:48:35 +0800561 /* Get the output format. */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800562 memset(&format, 0, sizeof(format));
563 format.type = ctx->capture_streamon_type;
564 ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
Alpha Linfa5caae2014-11-17 09:48:35 +0800565 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800566 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800567 init_param.output_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800568
Alpha Linfa5caae2014-11-17 09:48:35 +0800569 /* Get the cropped size. */
570 struct v4l2_crop crop;
571 memset(&crop, 0, sizeof(crop));
572 crop.type = ctx->output_streamon_type;
573 ret = SYS_IOCTL(fd, VIDIOC_G_CROP, &crop);
574 if (ret)
575 return ret;
576 init_param.width = crop.c.width;
577 init_param.height = crop.c.height;
578
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800579 /*
580 * If the encoder library has initialized and parameters have not
581 * changed, skip the initialization.
582 */
henryhsuc7c06f92014-11-24 15:57:08 +0800583 if (ctx->enc && memcmp(&init_param, &ctx->init_param, sizeof(init_param))) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800584 rk_vepu_deinit(ctx->enc);
henryhsuc7c06f92014-11-24 15:57:08 +0800585 ctx->enc = NULL;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800586 }
henryhsuc7c06f92014-11-24 15:57:08 +0800587 if (!ctx->enc) {
588 memcpy(&ctx->init_param, &init_param, sizeof(init_param));
589 ctx->enc = rk_vepu_init(&init_param);
590 if (ctx->enc == NULL) {
591 VLOG_FD(0, "Failed to initialize encoder library.");
592 return -EIO;
593 }
594 }
595 if (rk_vepu_update_parameter(ctx->enc, &ctx->runtime_param)) {
596 VLOG_FD(0, "rk_vepu_update_parameter failed.");
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800597 return -EIO;
598 }
henryhsuc7c06f92014-11-24 15:57:08 +0800599 memset(&ctx->runtime_param, 0, sizeof(struct rk_vepu_runtime_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800600 return 0;
601}
602
henryhsuc7c06f92014-11-24 15:57:08 +0800603static void queue_init(struct pending_buffer_queue *queue)
604{
605 memset(queue, 0, sizeof(struct pending_buffer_queue));
606}
607
608static bool queue_empty(struct pending_buffer_queue *queue)
609{
610 return queue->count == 0;
611}
612
613static bool queue_full(struct pending_buffer_queue *queue)
614{
615 return queue->count == PENDING_BUFFER_QUEUE_SIZE;
616}
617
618static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800619 struct v4l2_buffer *buffer)
620{
henryhsuc7c06f92014-11-24 15:57:08 +0800621 if (queue_full(queue))
622 return -ENOMEM;
623 int rear = (queue->front + queue->count) % PENDING_BUFFER_QUEUE_SIZE;
624 queue->count++;
625 struct pending_buffer *entry = &queue->buf_array[rear];
626 memset(entry, 0, sizeof(struct pending_buffer));
627
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800628 memcpy(&entry->buffer, buffer, sizeof(*buffer));
629 if (V4L2_TYPE_IS_MULTIPLANAR(buffer->type)) {
630 memset(entry->planes, 0,
631 sizeof(struct v4l2_plane) * VIDEO_MAX_PLANES);
632 memcpy(entry->planes, buffer->m.planes,
633 sizeof(struct v4l2_plane) * buffer->length);
634 entry->buffer.m.planes = entry->planes;
635 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800636 return 0;
637}
638
henryhsuc7c06f92014-11-24 15:57:08 +0800639static void queue_pop_front(struct pending_buffer_queue *queue)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800640{
henryhsuc7c06f92014-11-24 15:57:08 +0800641 assert(!queue_empty(queue));
642 queue->count--;
643 queue->front = (queue->front + 1) % PENDING_BUFFER_QUEUE_SIZE;
644}
645
646static struct pending_buffer *queue_front(struct pending_buffer_queue *queue)
647{
648 if (queue_empty(queue))
649 return NULL;
650 return &queue->buf_array[queue->front];
651}
652
653static struct pending_buffer *queue_back(struct pending_buffer_queue *queue)
654{
655 if (queue_empty(queue))
656 return NULL;
657 return &queue->buf_array[(queue->front + queue->count - 1) %
658 PENDING_BUFFER_QUEUE_SIZE];
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800659}
660
661static void get_log_level()
662{
663 char *log_level_str = getenv("LIBV4L_PLUGIN_LOG_LEVEL");
664 if (log_level_str != NULL)
665 g_log_level = strtol(log_level_str, NULL, 10);
666}
667
668static const char* v4l_cmd2str(unsigned long int cmd)
669{
670 switch (cmd) {
671 case VIDIOC_QUERYCAP:
672 return "VIDIOC_QUERYCAP";
673 case VIDIOC_TRY_FMT:
674 return "VIDIOC_TRY_FMT";
675 case VIDIOC_S_FMT:
676 return "VIDIOC_S_FMT";
677 case VIDIOC_G_FMT:
678 return "VIDIOC_G_FMT";
679 case VIDIOC_ENUM_FMT:
680 return "VIDIOC_ENUM_FMT";
681 case VIDIOC_S_PARM:
682 return "VIDIOC_S_PARM";
683 case VIDIOC_G_PARM:
684 return "VIDIOC_G_PARM";
685 case VIDIOC_QBUF:
686 return "VIDIOC_QBUF";
687 case VIDIOC_DQBUF:
688 return "VIDIOC_DQBUF";
689 case VIDIOC_PREPARE_BUF:
690 return "VIDIOC_PREPARE_BUF";
691 case VIDIOC_CREATE_BUFS:
692 return "VIDIOC_CREATE_BUFS";
693 case VIDIOC_REQBUFS:
694 return "VIDIOC_REQBUFS";
695 case VIDIOC_STREAMON:
696 return "VIDIOC_STREAMON";
697 case VIDIOC_STREAMOFF:
698 return "VIDIOC_STREAMOFF";
699 case VIDIOC_S_CROP:
700 return "VIDIOC_S_CROP";
701 case VIDIOC_S_CTRL:
702 return "VIDIOC_S_CTRL";
703 case VIDIOC_G_EXT_CTRLS:
704 return "VIDIOC_G_EXT_CTRLS";
705 case VIDIOC_S_EXT_CTRLS:
706 return "VIDIOC_S_EXT_CTRLS";
707 case VIDIOC_QUERYBUF:
708 return "VIDIOC_QUERYBUF";
709 default:
710 return "UNKNOWN";
711 }
henryhsu58be50c2014-10-30 11:49:19 +0800712}
713
714PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = {
715 .init = &plugin_init,
716 .close = &plugin_close,
717 .ioctl = &plugin_ioctl,
718};