blob: 2921c141e3c7c8b4de39bf6f187912b4c878c8b0 [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"
Wu-Cheng Lidcec4332014-11-13 15:49:21 +080019#include "libvpu/rk_vepu_interface.h"
henryhsu58be50c2014-10-30 11:49:19 +080020
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080021#define VLOG(log_level, str, ...) ((g_log_level >= log_level) ? \
22 (void) fprintf(stderr, "%s: " str "\n", __func__, ##__VA_ARGS__) \
23 : (void) 0)
24
25#define VLOG_FD(log_level, str, ...) ((g_log_level >= log_level) ? \
26 (void) fprintf(stderr, \
27 "%s: fd=%d. " str "\n", __func__, fd, ##__VA_ARGS__) : (void) 0)
28
29#define SYS_IOCTL(fd, cmd, arg) ({ \
30 int ret = syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), \
31 (void *)(arg)); \
henryhsuc7c06f92014-11-24 15:57:08 +080032 if ((ret && errno != EAGAIN) || g_log_level >= 2) \
33 fprintf(stderr, "SYS_ioctl: %s(%lu): fd=%d, ret=%d, errno=%d\n",\
34 v4l_cmd2str(cmd), _IOC_NR((unsigned long)cmd), fd, ret, \
35 errno); \
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080036 ret; \
37 })
henryhsu58be50c2014-10-30 11:49:19 +080038
39#if HAVE_VISIBILITY
40#define PLUGIN_PUBLIC __attribute__ ((__visibility__("default")))
41#else
42#define PLUGIN_PUBLIC
43#endif
44
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +080045#define RK3288_VPU_NAME "rk3288-vpu-enc"
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080046#define DEFAULT_FRAME_RATE 30
47#define DEFAULT_BITRATE 1000000
henryhsuc7c06f92014-11-24 15:57:08 +080048#define PENDING_BUFFER_QUEUE_SIZE VIDEO_MAX_FRAME
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080049
henryhsuc7c06f92014-11-24 15:57:08 +080050/*
51 * struct pending_buffer - A v4l2 buffer pending for QBUF.
52 * @buffer: v4l2 buffer for QBUF.
53 * @planes: plane info of v4l2 buffer.
54 * @next_runtime_param: runtime parameters like framerate, bitrate, and
55 * keyframe for the next buffer.
56 */
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080057struct pending_buffer {
58 struct v4l2_buffer buffer;
59 struct v4l2_plane planes[VIDEO_MAX_PLANES];
henryhsuc7c06f92014-11-24 15:57:08 +080060 struct rk_vepu_runtime_param next_runtime_param;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080061};
henryhsuc7c06f92014-11-24 15:57:08 +080062
63/*
64 * struct pending_buffer_queue - a ring buffer of pending buffers.
65 * @count: the number of buffers stored in the array.
66 * @front: the index of the first ready buffer.
67 * @buf_array: pending buffer array.
68 */
69struct pending_buffer_queue {
70 uint32_t count;
71 int32_t front;
72 struct pending_buffer buf_array[PENDING_BUFFER_QUEUE_SIZE];
73};
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080074
75/*
76 * struct encoder_context - the context of an encoder instance.
77 * @enc: Encoder instance returned from rk_vepu_create().
78 * @mutex: The mutex to protect encoder_context.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080079 * @output_streamon_type: Type of output interface when it streams on.
80 * @capture_streamon_type: Type of capture interface when it streams on.
henryhsuc7c06f92014-11-24 15:57:08 +080081 * @init_param: Encoding parameters like input format, resolution, and etc.
82 * These parameters will be passed to encoder at libvpu
83 * initialization.
84 * @runtime_param: Runtime parameters like framerate, bitrate, and
85 * keyframe. This is only used for receiving ext_ctrls
86 * before streamon and pending buffer queue is empty.
Wu-Cheng Lice8947e2014-11-13 17:34:16 +080087 * @pending_buffers: The pending v4l2 buffers waiting for the encoding
88 * configuration. After a previous buffer is dequeued,
89 * one buffer from the queue can be queued.
90 * @can_qbuf: Indicate that we can queue one source buffer. This is true only
91 * when the parameters to pass together with the source buffer are
92 * ready; those params are received on dequeing the previous
93 * destination buffer.
94 * @get_param_payload: Payload of V4L2_CID_PRIVATE_RK3288_GET_PARAMS. This is
95 * used to update the encoder configuration by
96 * rk_vepu_update_config().
97 * @get_param_payload_size: The size of get_param_payload.
98 * @v4l2_ctrls: v4l2 controls for VIDIOC_S_EXT_CTRLS.
99 */
100struct encoder_context {
101 void *enc;
102 pthread_mutex_t mutex;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800103 enum v4l2_buf_type output_streamon_type;
104 enum v4l2_buf_type capture_streamon_type;
henryhsuc7c06f92014-11-24 15:57:08 +0800105 struct rk_vepu_init_param init_param;
106 struct rk_vepu_runtime_param runtime_param;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800107 struct pending_buffer_queue pending_buffers;
108 bool can_qbuf;
109 void *get_param_payload;
110 size_t get_param_payload_size;
111 struct v4l2_ext_control v4l2_ctrls[MAX_NUM_GET_CONFIG_CTRLS];
112};
113
114static void *plugin_init(int fd);
115static void plugin_close(void *dev_ops_priv);
116static int plugin_ioctl(void *dev_ops_priv, int fd, unsigned long int cmd,
117 void *arg);
118
119/* Functions to handle various ioctl. */
120static int ioctl_streamon_locked(
121 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
122static int ioctl_streamoff_locked(
123 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
124static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
125 struct v4l2_buffer *buffer);
126static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
127 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800128static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
129 struct v4l2_ext_controls *ext_ctrls);
130static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
131 struct v4l2_streamparm *parms);
132static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
133 struct v4l2_requestbuffers *reqbufs);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800134
135/* Helper functions to manipulate the pending buffer queue. */
136
henryhsuc7c06f92014-11-24 15:57:08 +0800137static void queue_init(struct pending_buffer_queue *queue);
138static bool queue_empty(struct pending_buffer_queue *queue);
139static bool queue_full(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800140/* Insert a buffer to the tail of the queue. */
henryhsuc7c06f92014-11-24 15:57:08 +0800141static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800142 struct v4l2_buffer *buffer);
henryhsuc7c06f92014-11-24 15:57:08 +0800143/* Remove a buffer from the head of the queue. */
144static void queue_pop_front(struct pending_buffer_queue *queue);
145static struct pending_buffer *queue_front(struct pending_buffer_queue *queue);
146static struct pending_buffer *queue_back(struct pending_buffer_queue *queue);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800147
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800148/* Returns true if the fd is Rockchip encoder device. */
149bool is_rockchip_encoder(int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800150/* Set encoder configuration to the driver. */
henryhsuc7c06f92014-11-24 15:57:08 +0800151int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800152 uint32_t buffer_index, size_t num_ctrls, uint32_t ctrls_ids[],
153 void **payloads, uint32_t payload_sizes[]);
154/* QBUF a buffer from the pending buffer queue if it is not empty. */
henryhsuc7c06f92014-11-24 15:57:08 +0800155static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
156 int fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800157/* Get the encoder parameters using G_FMT and initialize libvpu. */
158static int initialize_libvpu(struct encoder_context *ctx, int fd);
159/* Return the string represenation of a libv4l command for debugging. */
160static const char *v4l_cmd2str(unsigned long int cmd);
161/*
162 * The current log level for VLOG. This is read from environment variable
163 * LIBV4L_PLUGIN_LOG_LEVEL every time plugin_init is called.
164 */
165static int g_log_level = 0;
166/* Get the log level from the environment variable. */
167static void get_log_level();
168static pthread_once_t g_get_log_level_once = PTHREAD_ONCE_INIT;
169
henryhsu58be50c2014-10-30 11:49:19 +0800170static void *plugin_init(int fd)
171{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800172 int ret;
173 struct v4l2_query_ext_ctrl ext_ctrl;
174
175 pthread_once(&g_get_log_level_once, get_log_level);
176
177 VLOG_FD(1, "");
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800178 if (!is_rockchip_encoder(fd))
179 return NULL;
180
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800181 struct encoder_context *ctx = (struct encoder_context *)
182 calloc(1, sizeof(struct encoder_context));
183 if (ctx == NULL) {
184 errno = ENOMEM;
185 goto fail;
186 }
187 ret = pthread_mutex_init(&ctx->mutex, NULL);
188 if (ret)
189 goto fail;
henryhsuc7c06f92014-11-24 15:57:08 +0800190 queue_init(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800191
192 memset(&ext_ctrl, 0, sizeof(ext_ctrl));
193 ext_ctrl.id = V4L2_CID_PRIVATE_RK3288_GET_PARAMS;
194 ret = SYS_IOCTL(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl);
195 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800196 goto fail;
197 }
198 ctx->get_param_payload_size = ext_ctrl.elem_size;
199 ctx->get_param_payload = calloc(1, ctx->get_param_payload_size);
200 if (ctx->get_param_payload == NULL) {
201 errno = ENOMEM;
202 goto fail;
203 }
henryhsuc7c06f92014-11-24 15:57:08 +0800204 ctx->runtime_param.framerate_numer = DEFAULT_FRAME_RATE;
205 ctx->runtime_param.framerate_denom = 1;
206 ctx->runtime_param.bitrate = DEFAULT_BITRATE;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800207 VLOG_FD(1, "Success. ctx=%p", ctx);
208 return ctx;
209
210fail:
211 plugin_close(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800212 return NULL;
213}
214
215static void plugin_close(void *dev_ops_priv)
216{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800217 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
218
219 VLOG(1, "ctx=%p", ctx);
220 if (ctx == NULL)
221 return;
222
223 pthread_mutex_lock(&ctx->mutex);
224 if (ctx->enc)
225 rk_vepu_deinit(ctx->enc);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800226 free(ctx->get_param_payload);
227 ctx->get_param_payload = NULL;
228 pthread_mutex_unlock(&ctx->mutex);
229 pthread_mutex_destroy(&ctx->mutex);
230
231 free(ctx);
henryhsu58be50c2014-10-30 11:49:19 +0800232}
233
234static int plugin_ioctl(void *dev_ops_priv, int fd,
235 unsigned long int cmd, void *arg)
236{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800237 int ret;
238 struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
239
240 VLOG_FD(1, "%s(%lu)", v4l_cmd2str(cmd), _IOC_NR(cmd));
241
242 pthread_mutex_lock(&ctx->mutex);
243 switch (cmd) {
244 case VIDIOC_STREAMON:
henryhsuc7c06f92014-11-24 15:57:08 +0800245 ret = ioctl_streamon_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800246 break;
247
248 case VIDIOC_STREAMOFF:
henryhsuc7c06f92014-11-24 15:57:08 +0800249 ret = ioctl_streamoff_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800250 break;
251
252 case VIDIOC_QBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800253 ret = ioctl_qbuf_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800254 break;
255
256 case VIDIOC_DQBUF:
henryhsuc7c06f92014-11-24 15:57:08 +0800257 ret = ioctl_dqbuf_locked(ctx, fd, arg);
258 break;
259
260 case VIDIOC_S_EXT_CTRLS:
261 ret = ioctl_s_ext_ctrls_locked(ctx, fd, arg);
262 break;
263
264 case VIDIOC_S_PARM:
265 ret = ioctl_s_parm_locked(ctx, fd, arg);
266 break;
267
268 case VIDIOC_REQBUFS:
269 ret = ioctl_reqbufs_locked(ctx, fd, arg);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800270 break;
271
272 default:
273 ret = SYS_IOCTL(fd, cmd, arg);
274 break;
275 }
276 pthread_mutex_unlock(&ctx->mutex);
277 return ret;
278}
279
280static int ioctl_streamon_locked(
281 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
282{
283 int ret = SYS_IOCTL(fd, VIDIOC_STREAMON, type);
284 if (ret)
285 return ret;
286
287 if (V4L2_TYPE_IS_OUTPUT(*type))
288 ctx->output_streamon_type = *type;
289 else
290 ctx->capture_streamon_type = *type;
291 if (ctx->output_streamon_type && ctx->capture_streamon_type) {
292 ret = initialize_libvpu(ctx, fd);
293 if (ret)
294 return ret;
295 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800296 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800297 }
298 return 0;
299}
300
301static int ioctl_streamoff_locked(
302 struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
303{
304 int ret = SYS_IOCTL(fd, VIDIOC_STREAMOFF, type);
305 if (ret)
306 return ret;
307
308 if (V4L2_TYPE_IS_OUTPUT(*type))
309 ctx->output_streamon_type = 0;
310 else
311 ctx->capture_streamon_type = 0;
312 return 0;
313}
314
315static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
316 struct v4l2_buffer *buffer)
317{
318 size_t num_ctrls = 0;
319 uint32_t *ctrl_ids = NULL, *payload_sizes = NULL;
320 void **payloads = NULL;
321 int ret;
322
323 if (!V4L2_TYPE_IS_OUTPUT(buffer->type)) {
324 return SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
325 }
326
327 if (!ctx->can_qbuf) {
328 VLOG_FD(1, "Put buffer (%d) in the pending queue.",
329 buffer->index);
330 /*
331 * The last frame is not encoded yet. Put the buffer to the
332 * pending queue.
333 */
henryhsuc7c06f92014-11-24 15:57:08 +0800334 return queue_push_back(&ctx->pending_buffers, buffer);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800335 }
336 /* Get the encoder configuration from the library. */
337 if (rk_vepu_get_config(ctx->enc, &num_ctrls, &ctrl_ids, &payloads,
338 &payload_sizes)) {
339 VLOG_FD(0, "rk_vepu_get_config failed");
340 return -EIO;
341 }
342 /* Set the encoder configuration to the driver. */
henryhsuc7c06f92014-11-24 15:57:08 +0800343 ret = set_encoder_config_locked(ctx, fd, buffer->index, num_ctrls, ctrl_ids,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800344 payloads, payload_sizes);
345 if (ret)
346 return ret;
347
Jeffy Chen756f2a42014-12-15 10:32:22 +0800348 /* TODO: change this to config_store after the header is updated. */
349 buffer->reserved2 = buffer->index + 1;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800350 ret = SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
351 if (ret == 0)
352 ctx->can_qbuf = false;
353 else
354 VLOG(0, "QBUF failed. errno=%d", errno);
355 return ret;
356}
357
358static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
359 struct v4l2_buffer *buffer)
360{
361 struct v4l2_ext_controls ext_ctrls;
362 struct v4l2_ext_control v4l2_ctrl;
363 int ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800364 uint32_t bytesused;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800365
366 if (V4L2_TYPE_IS_OUTPUT(buffer->type)) {
367 return SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
368 }
369
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800370 ret = SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
371 if (ret)
372 return ret;
373
Wu-Cheng Lif1e616b2014-11-21 15:11:34 +0800374 assert(!ctx->can_qbuf);
375
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800376 /* Get the encoder configuration and update the library. */
377 memset(ctx->get_param_payload, 0, ctx->get_param_payload_size);
378 memset(&v4l2_ctrl, 0, sizeof(v4l2_ctrl));
379 v4l2_ctrl.id = V4L2_CID_PRIVATE_RK3288_GET_PARAMS;
380 v4l2_ctrl.size = ctx->get_param_payload_size;
Wu-Cheng Liadc8ec82014-11-21 15:51:59 +0800381 v4l2_ctrl.ptr = ctx->get_param_payload;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800382 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
383 /* TODO: change this to config_store after the header is updated. */
henryhsuc7c06f92014-11-24 15:57:08 +0800384 ext_ctrls.ctrl_class = 0;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800385 ext_ctrls.count = 1;
386 ext_ctrls.controls = &v4l2_ctrl;
387 ret = SYS_IOCTL(fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls);
henryhsuc7c06f92014-11-24 15:57:08 +0800388 if (ret)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800389 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800390 bytesused = V4L2_TYPE_IS_MULTIPLANAR(buffer->type) ?
391 buffer->m.planes[0].bytesused : buffer->bytesused;
392
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800393 if (rk_vepu_update_config(ctx->enc, v4l2_ctrl.ptr, v4l2_ctrl.size,
henryhsuc7c06f92014-11-24 15:57:08 +0800394 bytesused)) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800395 VLOG_FD(0, "rk_vepu_update_config failed.");
396 return -EIO;
397 }
398 ctx->can_qbuf = true;
henryhsuc7c06f92014-11-24 15:57:08 +0800399 return qbuf_if_pending_buffer_exists_locked(ctx, fd);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800400}
401
henryhsuc7c06f92014-11-24 15:57:08 +0800402static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
403 struct v4l2_ext_controls *ext_ctrls)
404{
405 size_t i;
406 struct rk_vepu_runtime_param *runtime_param_ptr;
407
408 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
409 /*
410 * If buffer queue is empty, update parameters directly.
411 * If buffer queue is not empty, save parameters to the last buffer. And
412 * these values will be sent again when the buffer is ready to deliver.
413 */
414 if (!no_pending_buffer) {
415 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
416 runtime_param_ptr = &element->next_runtime_param;
417 } else {
418 runtime_param_ptr = &ctx->runtime_param;
419 }
420
421 /*
422 * Check each extension control to update keyframe and bitrate
423 * parameters.
424 */
425 for (i = 0; i < ext_ctrls->count; i++) {
426 switch (ext_ctrls->controls[i].id) {
427 case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
428 if (ext_ctrls->controls[i].value ==
429 V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED)
430 break;
431 runtime_param_ptr->keyframe_request = true;
432 runtime_param_ptr->keyframe_value = (ext_ctrls->controls[i].value ==
433 V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME);
434 break;
435 case V4L2_CID_MPEG_VIDEO_BITRATE:
436 runtime_param_ptr->bitrate = ext_ctrls->controls[i].value;
437 break;
438 default:
439 break;
440 }
441 }
442
443 if (no_pending_buffer && ctx->enc) {
444 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
445 VLOG_FD(0, "rk_vepu_update_parameter failed.");
446 return -EIO;
447 }
448 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
449 }
450 /* Driver should ignore keyframe and bitrate controls */
451 return SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, ext_ctrls);
452}
453
454static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
455 struct v4l2_streamparm *parms)
456{
457 if (V4L2_TYPE_IS_OUTPUT(parms->type)
458 && parms->parm.output.timeperframe.denominator) {
459 struct rk_vepu_runtime_param *runtime_param_ptr;
460 bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
461 struct pending_buffer *element = queue_back(&ctx->pending_buffers);
462
463 runtime_param_ptr = no_pending_buffer ? &ctx->runtime_param :
464 &element->next_runtime_param;
465 runtime_param_ptr->framerate_numer =
466 parms->parm.output.timeperframe.denominator;
467 runtime_param_ptr->framerate_denom =
468 parms->parm.output.timeperframe.numerator;
469
470 if (!no_pending_buffer || !ctx->enc)
471 return 0;
472 if (rk_vepu_update_parameter(ctx->enc, runtime_param_ptr)) {
473 VLOG_FD(0, "rk_vepu_update_parameter failed.");
474 return -EIO;
475 }
476 memset(runtime_param_ptr, 0, sizeof(struct rk_vepu_runtime_param));
477 return 0;
478 }
479 return SYS_IOCTL(fd, VIDIOC_S_PARM, parms);
480}
481
482static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
483 struct v4l2_requestbuffers *reqbufs)
484{
485 int ret = SYS_IOCTL(fd, VIDIOC_REQBUFS, reqbufs);
486 if (ret)
487 return ret;
488 queue_init(&ctx->pending_buffers);
489 return 0;
490}
491
Wu-Cheng Li11ae3aa2014-12-18 17:11:48 +0800492bool is_rockchip_encoder(int fd) {
493 struct v4l2_capability cap;
494 memset(&cap, 0, sizeof(cap));
495 int ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
496 if (ret)
497 return false;
498 return strcmp(RK3288_VPU_NAME, cap.driver) == 0;
499}
500
henryhsuc7c06f92014-11-24 15:57:08 +0800501int set_encoder_config_locked(struct encoder_context *ctx, int fd,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800502 uint32_t buffer_index, size_t num_ctrls, uint32_t ctrl_ids[],
henryhsuc7c06f92014-11-24 15:57:08 +0800503 void **payloads, uint32_t payload_sizes[])
504{
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800505 size_t i;
506 struct v4l2_ext_controls ext_ctrls;
507
508 if (num_ctrls <= 0)
509 return 0;
510
511 assert(num_ctrls <= MAX_NUM_GET_CONFIG_CTRLS);
henryhsuc7c06f92014-11-24 15:57:08 +0800512 if (num_ctrls > MAX_NUM_GET_CONFIG_CTRLS) {
513 VLOG_FD(0, "The number of controls exceeds limit.");
514 return -EIO;
515 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800516 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
517 /* TODO: change this to config_store after the header is updated. */
518 ext_ctrls.ctrl_class = buffer_index + 1;
519 ext_ctrls.count = num_ctrls;
520 ext_ctrls.controls = ctx->v4l2_ctrls;
521 memset(ctx->v4l2_ctrls, 0, sizeof(ctx->v4l2_ctrls));
522 for (i = 0; i < num_ctrls; ++i) {
523 ctx->v4l2_ctrls[i].id = ctrl_ids[i];
524 ctx->v4l2_ctrls[i].ptr = payloads[i];
525 ctx->v4l2_ctrls[i].size = payload_sizes[i];
526 }
527 int ret = SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, &ext_ctrls);
528 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800529 return ret;
530 }
531 return 0;
532}
533
henryhsuc7c06f92014-11-24 15:57:08 +0800534static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
535 int fd)
536{
537 if (!queue_empty(&ctx->pending_buffers)) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800538 int ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800539 struct pending_buffer *element = queue_front(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800540 VLOG_FD(1, "QBUF a buffer (%d) from the pending queue.",
541 element->buffer.index);
henryhsuc7c06f92014-11-24 15:57:08 +0800542 if (rk_vepu_update_parameter(ctx->enc, &element->next_runtime_param)) {
543 VLOG_FD(0, "rk_vepu_update_parameter failed.");
544 return -EIO;
545 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800546 ret = ioctl_qbuf_locked(ctx, fd, &element->buffer);
547 if (ret)
548 return ret;
henryhsuc7c06f92014-11-24 15:57:08 +0800549 queue_pop_front(&ctx->pending_buffers);
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800550 }
551 return 0;
552}
553
henryhsuc7c06f92014-11-24 15:57:08 +0800554static int initialize_libvpu(struct encoder_context *ctx, int fd)
555{
556 struct rk_vepu_init_param init_param;
557 memset(&init_param, 0, sizeof(init_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800558
559 struct v4l2_format format;
560 memset(&format, 0, sizeof(format));
561 format.type = ctx->output_streamon_type;
562 int ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
563 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800564 return ret;
565 }
henryhsuc7c06f92014-11-24 15:57:08 +0800566 init_param.width = format.fmt.pix_mp.width;
567 init_param.height = format.fmt.pix_mp.height;
568 init_param.input_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800569
570 memset(&format, 0, sizeof(format));
571 format.type = ctx->capture_streamon_type;
572 ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
573 if (ret) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800574 return ret;
575 }
henryhsuc7c06f92014-11-24 15:57:08 +0800576 init_param.output_format = format.fmt.pix_mp.pixelformat;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800577
578 /*
579 * If the encoder library has initialized and parameters have not
580 * changed, skip the initialization.
581 */
henryhsuc7c06f92014-11-24 15:57:08 +0800582 if (ctx->enc && memcmp(&init_param, &ctx->init_param, sizeof(init_param))) {
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800583 rk_vepu_deinit(ctx->enc);
henryhsuc7c06f92014-11-24 15:57:08 +0800584 ctx->enc = NULL;
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800585 }
henryhsuc7c06f92014-11-24 15:57:08 +0800586 if (!ctx->enc) {
587 memcpy(&ctx->init_param, &init_param, sizeof(init_param));
588 ctx->enc = rk_vepu_init(&init_param);
589 if (ctx->enc == NULL) {
590 VLOG_FD(0, "Failed to initialize encoder library.");
591 return -EIO;
592 }
593 }
594 if (rk_vepu_update_parameter(ctx->enc, &ctx->runtime_param)) {
595 VLOG_FD(0, "rk_vepu_update_parameter failed.");
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800596 return -EIO;
597 }
henryhsuc7c06f92014-11-24 15:57:08 +0800598 memset(&ctx->runtime_param, 0, sizeof(struct rk_vepu_runtime_param));
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800599 return 0;
600}
601
henryhsuc7c06f92014-11-24 15:57:08 +0800602static void queue_init(struct pending_buffer_queue *queue)
603{
604 memset(queue, 0, sizeof(struct pending_buffer_queue));
605}
606
607static bool queue_empty(struct pending_buffer_queue *queue)
608{
609 return queue->count == 0;
610}
611
612static bool queue_full(struct pending_buffer_queue *queue)
613{
614 return queue->count == PENDING_BUFFER_QUEUE_SIZE;
615}
616
617static int queue_push_back(struct pending_buffer_queue *queue,
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800618 struct v4l2_buffer *buffer)
619{
henryhsuc7c06f92014-11-24 15:57:08 +0800620 if (queue_full(queue))
621 return -ENOMEM;
622 int rear = (queue->front + queue->count) % PENDING_BUFFER_QUEUE_SIZE;
623 queue->count++;
624 struct pending_buffer *entry = &queue->buf_array[rear];
625 memset(entry, 0, sizeof(struct pending_buffer));
626
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800627 memcpy(&entry->buffer, buffer, sizeof(*buffer));
628 if (V4L2_TYPE_IS_MULTIPLANAR(buffer->type)) {
629 memset(entry->planes, 0,
630 sizeof(struct v4l2_plane) * VIDEO_MAX_PLANES);
631 memcpy(entry->planes, buffer->m.planes,
632 sizeof(struct v4l2_plane) * buffer->length);
633 entry->buffer.m.planes = entry->planes;
634 }
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800635 return 0;
636}
637
henryhsuc7c06f92014-11-24 15:57:08 +0800638static void queue_pop_front(struct pending_buffer_queue *queue)
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800639{
henryhsuc7c06f92014-11-24 15:57:08 +0800640 assert(!queue_empty(queue));
641 queue->count--;
642 queue->front = (queue->front + 1) % PENDING_BUFFER_QUEUE_SIZE;
643}
644
645static struct pending_buffer *queue_front(struct pending_buffer_queue *queue)
646{
647 if (queue_empty(queue))
648 return NULL;
649 return &queue->buf_array[queue->front];
650}
651
652static struct pending_buffer *queue_back(struct pending_buffer_queue *queue)
653{
654 if (queue_empty(queue))
655 return NULL;
656 return &queue->buf_array[(queue->front + queue->count - 1) %
657 PENDING_BUFFER_QUEUE_SIZE];
Wu-Cheng Lice8947e2014-11-13 17:34:16 +0800658}
659
660static void get_log_level()
661{
662 char *log_level_str = getenv("LIBV4L_PLUGIN_LOG_LEVEL");
663 if (log_level_str != NULL)
664 g_log_level = strtol(log_level_str, NULL, 10);
665}
666
667static const char* v4l_cmd2str(unsigned long int cmd)
668{
669 switch (cmd) {
670 case VIDIOC_QUERYCAP:
671 return "VIDIOC_QUERYCAP";
672 case VIDIOC_TRY_FMT:
673 return "VIDIOC_TRY_FMT";
674 case VIDIOC_S_FMT:
675 return "VIDIOC_S_FMT";
676 case VIDIOC_G_FMT:
677 return "VIDIOC_G_FMT";
678 case VIDIOC_ENUM_FMT:
679 return "VIDIOC_ENUM_FMT";
680 case VIDIOC_S_PARM:
681 return "VIDIOC_S_PARM";
682 case VIDIOC_G_PARM:
683 return "VIDIOC_G_PARM";
684 case VIDIOC_QBUF:
685 return "VIDIOC_QBUF";
686 case VIDIOC_DQBUF:
687 return "VIDIOC_DQBUF";
688 case VIDIOC_PREPARE_BUF:
689 return "VIDIOC_PREPARE_BUF";
690 case VIDIOC_CREATE_BUFS:
691 return "VIDIOC_CREATE_BUFS";
692 case VIDIOC_REQBUFS:
693 return "VIDIOC_REQBUFS";
694 case VIDIOC_STREAMON:
695 return "VIDIOC_STREAMON";
696 case VIDIOC_STREAMOFF:
697 return "VIDIOC_STREAMOFF";
698 case VIDIOC_S_CROP:
699 return "VIDIOC_S_CROP";
700 case VIDIOC_S_CTRL:
701 return "VIDIOC_S_CTRL";
702 case VIDIOC_G_EXT_CTRLS:
703 return "VIDIOC_G_EXT_CTRLS";
704 case VIDIOC_S_EXT_CTRLS:
705 return "VIDIOC_S_EXT_CTRLS";
706 case VIDIOC_QUERYBUF:
707 return "VIDIOC_QUERYBUF";
708 default:
709 return "UNKNOWN";
710 }
henryhsu58be50c2014-10-30 11:49:19 +0800711}
712
713PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = {
714 .init = &plugin_init,
715 .close = &plugin_close,
716 .ioctl = &plugin_ioctl,
717};