blob: a157fec03c7f447654a05af13ba36bfe19c15dae [file] [log] [blame]
Song Zhao1b237602020-02-13 10:58:57 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
9#include <errno.h>
10#include <stdlib.h>
11#include <string.h>
12#include <stdio.h>
13#include <stdbool.h>
14#include <pthread.h>
15#include <semaphore.h>
16#include <poll.h>
17#include <linux/videodev2.h>
18#include <sys/ioctl.h>
19#include <sys/mman.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <unistd.h>
24
25#include "aml_driver.h"
26#include "demux.h"
27#include "drm.h"
28#include "v4l2-dec.h"
Song Zhaoec315042020-06-12 00:51:42 -070029#ifdef CONFIG_SECMEM
Song Zhao6c7d1f82020-04-06 23:22:49 -070030#include "secmem.h"
Song Zhaoec315042020-06-12 00:51:42 -070031#endif
Song Zhao33f4cc32020-05-02 22:13:24 -070032#include "vp9.h"
Song Zhao1b237602020-02-13 10:58:57 -080033
34static const char* video_dev_name = "/dev/video26";
35static int video_fd;
36static bool get_1st_data = false;
37static int cur_output_index = -1;
38static decode_finish_fn decode_finish_cb;
39static bool res_evt_pending;
40static bool eos_evt_pending;
41static bool eos_received;
42extern int g_dw_mode;
43static pthread_mutex_t res_lock;
Song Zhao6c7d1f82020-04-06 23:22:49 -070044static enum v4l2_memory sInMemMode;
45static uint8_t* es_buf;
Song Zhao1b237602020-02-13 10:58:57 -080046//#define DEBUG_FRAME
47#ifdef DEBUG_FRAME
48static int frame_checksum;
49#endif
Song Zhao4090efb2020-05-14 15:02:10 -070050#define ES_BUF_SIZE (4*1024*1024)
Song Zhao1b237602020-02-13 10:58:57 -080051
52static pthread_t dec_thread;
53bool quit_thread;
54extern int config_sys_node(const char* path, const char* value);
55extern int span(struct timeval* t1, struct timeval* t2);
56
57struct frame_buffer {
58 struct v4l2_buffer v4lbuf;
59 struct v4l2_plane v4lplane[2];
60 uint8_t *vaddr[2];
61 int gem_fd[2];
62 bool queued;
63
64 /* output only */
65 uint32_t used;
Song Zhao6c7d1f82020-04-06 23:22:49 -070066 struct secmem* smem;
67
Song Zhao1b237602020-02-13 10:58:57 -080068 /* capture only */
69 bool free_on_recycle;
70 struct drm_frame *drm_frame;
71};
72
73struct port_config {
74 enum v4l2_buf_type type;
75 uint32_t pixelformat;
76 struct v4l2_format sfmt;
77 int buf_num;
78 int plane_num;
79 struct frame_buffer** buf;
80 pthread_mutex_t lock;
81 pthread_cond_t wait;
82};
83
84#define OUTPUT_BUF_CNT 4
85static struct port_config output_p;
86static struct port_config capture_p;
87
88static int d_o_push_num;
89static int d_o_rec_num;
90static int d_c_push_num;
91static int d_c_rec_num;
92
93struct profile {
94 bool res_change;
95 struct timeval last_flag;
96 struct timeval buffer_done;
97 struct timeval first_frame;
98};
99static struct profile res_profile;
100
101static enum vtype v4l2_fourcc_to_vtype(uint32_t fourcc) {
102 switch (fourcc) {
103 case V4L2_PIX_FMT_H264:
104 return VIDEO_TYPE_H264;
105 case V4L2_PIX_FMT_HEVC:
106 return VIDEO_TYPE_H265;
107 case V4L2_PIX_FMT_VP9:
108 return VIDEO_TYPE_VP9;
109 case V4L2_PIX_FMT_MPEG2:
110 return VIDEO_TYPE_MPEG2;
111 }
112 return VIDEO_TYPE_MAX;
113}
114
115static uint32_t get_driver_min_buffers (int fd, bool capture_port)
116{
117 struct v4l2_control control = { 0, };
118
119 if (!capture_port)
120 control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
121 else
122 control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
123
124 if (!ioctl(fd, VIDIOC_G_CTRL, &control))
125 return control.value;
126
127 return 0;
128}
129
130static int setup_output_port(int fd)
131{
132 int i,ret;
133 struct v4l2_requestbuffers req;
134
135 req.count = get_driver_min_buffers(fd, false);
136 if (!req.count) {
137 printf("fail to get min buffers for output, use default\n");
138 req.count = OUTPUT_BUF_CNT;
139 }
140
Song Zhao6c7d1f82020-04-06 23:22:49 -0700141 req.memory = sInMemMode;
Song Zhao1b237602020-02-13 10:58:57 -0800142 req.type = output_p.type;
143
144 ret = ioctl(fd, VIDIOC_REQBUFS, &req);
145 if (ret < 0) {
146 printf("output VIDIOC_REQBUFS fail ret:%d\n", ret);
147 return 1;
148 }
149 output_p.buf_num = req.count;
150 printf("output gets %d buf\n", req.count);
151
152 output_p.buf = calloc(req.count, sizeof(struct frame_buffer *));
153 if (!output_p.buf) {
154 printf("%d oom\n", __LINE__);
155 return 2;
156 }
157 for (i = 0 ; i < req.count ; i++)
158 output_p.buf[i] = calloc(1, sizeof(struct frame_buffer));
159
160 for (i = 0; i < req.count; i++) {
161 int j;
162 struct frame_buffer* pb = output_p.buf[i];
163 pb->v4lbuf.index = i;
164 pb->v4lbuf.type = output_p.type;
Song Zhao6c7d1f82020-04-06 23:22:49 -0700165 pb->v4lbuf.memory = sInMemMode;
Song Zhao1b237602020-02-13 10:58:57 -0800166 pb->v4lbuf.length = output_p.plane_num;
167 pb->v4lbuf.m.planes = pb->v4lplane;
168
169 ret = ioctl(fd, VIDIOC_QUERYBUF, &pb->v4lbuf);
170 if (ret) {
171 printf("VIDIOC_QUERYBUF %dth buf fail ret:%d\n", i, ret);
172 return 3;
173 }
Song Zhao6c7d1f82020-04-06 23:22:49 -0700174
175 if (sInMemMode != V4L2_MEMORY_MMAP)
176 continue;
Song Zhao1b237602020-02-13 10:58:57 -0800177 for (j = 0; j < output_p.plane_num; j++) {
178 void *vaddr;
179 vaddr = mmap(NULL, pb->v4lplane[j].length,
180 PROT_READ | PROT_WRITE, MAP_SHARED,
181 fd, pb->v4lplane[j].m.mem_offset);
182 if (vaddr == MAP_FAILED) {
183 printf("%s mmap faild len:%d offset:%x\n", __func__,
184 pb->v4lplane[j].length, pb->v4lplane[j].m.mem_offset);
185 return 4;
186 }
187 pb->vaddr[j] = (uint8_t *)vaddr;
188 }
189
190 }
191
192 pthread_mutex_init(&output_p.lock, NULL);
193 pthread_cond_init(&output_p.wait, NULL);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700194
195 if (sInMemMode == V4L2_MEMORY_DMABUF) {
196 es_buf = malloc(ES_BUF_SIZE);
197 if (!es_buf) {
198 printf("%d OOM\n", __LINE__);
199 return 5;
200 }
201 }
Song Zhao1b237602020-02-13 10:58:57 -0800202 return 0;
203}
204
205static int destroy_output_port(int fd) {
206 int i;
207 struct v4l2_requestbuffers req = {
Song Zhao6c7d1f82020-04-06 23:22:49 -0700208 .memory = sInMemMode,
Song Zhao1b237602020-02-13 10:58:57 -0800209 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
210 .count = 0,
211 };
212 pthread_mutex_destroy(&output_p.lock);
213 pthread_cond_destroy(&output_p.wait);
214 ioctl(fd, VIDIOC_REQBUFS, &req);
215 for (i = 0 ; i < req.count ; i++) {
216 struct frame_buffer *buf = output_p.buf[i];
217
Song Zhaoec315042020-06-12 00:51:42 -0700218#ifdef CONFIG_SECMEM
Song Zhao6c7d1f82020-04-06 23:22:49 -0700219 if (sInMemMode == V4L2_MEMORY_DMABUF)
220 secmem_free(buf->smem);
Song Zhaoec315042020-06-12 00:51:42 -0700221#endif
Song Zhao6c7d1f82020-04-06 23:22:49 -0700222
Song Zhao1b237602020-02-13 10:58:57 -0800223 free(buf);
224 }
225 free(output_p.buf);
226 return 0;
227}
228
229static int setup_capture_port(int fd)
230{
231 int i,ret;
232 uint32_t coded_w, coded_h;
233 struct v4l2_requestbuffers req;
234
235
236 /* coded size should be ready now */
237 memset(&capture_p.sfmt, 0, sizeof(struct v4l2_format));
238 capture_p.sfmt.type = capture_p.type;
239 ret = ioctl(video_fd, VIDIOC_G_FMT, &capture_p.sfmt);
240 if (ret) {
241 printf("%d VIDIOC_G_FMT fail :%d\n", __LINE__, ret);
242 return -1;
243 }
244 coded_w = capture_p.sfmt.fmt.pix_mp.width;
245 coded_h = capture_p.sfmt.fmt.pix_mp.height;
246 printf("capture port (%dx%d)\n", coded_w, coded_h);
247
248 if (g_dw_mode != VDEC_DW_AFBC_ONLY)
249 capture_p.sfmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
250 else
251 capture_p.sfmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
252 ret = ioctl(video_fd, VIDIOC_S_FMT, &capture_p.sfmt);
253 if (ret) {
254 printf("VIDIOC_S_FMT fail %d\n", ret);
255 return -1;
256 }
257 printf("set capture port to %s\n",
258 (g_dw_mode == VDEC_DW_AFBC_ONLY)?"NV12":"NV12M");
259 capture_p.plane_num = capture_p.sfmt.fmt.pix_mp.num_planes;
260 printf("number of capture plane: %d\n", capture_p.plane_num);
261
262 memset(&req, 0 , sizeof(req));
263 req.memory = V4L2_MEMORY_DMABUF;
264 req.type = capture_p.type;
265 req.count = get_driver_min_buffers(fd, true);
266 if (!req.count) {
267 printf("get min buffers fail\n");
268 return -1;
269 }
270
271 printf("req capture count:%d\n", req.count);
272 ret = ioctl(fd, VIDIOC_REQBUFS, &req);
273 if (ret < 0) {
274 printf("capture VIDIOC_REQBUFS fail ret:%d\n", ret);
275 return 1;
276 }
277 capture_p.buf_num = req.count;
278 printf("capture gets %d buf\n", req.count);
279
280 capture_p.buf = calloc(req.count, sizeof(struct frame_buffer *));
281 if (!capture_p.buf) {
282 printf("%d oom\n", __LINE__);
283 return 2;
284 }
285 for (i = 0 ; i < req.count ; i++) {
286 capture_p.buf[i] = calloc(1, sizeof(struct frame_buffer));
287 if (!capture_p.buf[i]) {
288 printf("%d oom\n", __LINE__);
289 return 2;
290 }
291 }
292
293 for (i = 0; i < req.count; i++) {
294 struct frame_buffer* pb = capture_p.buf[i];
295 int fd[4] = {0}, j;
296
297 pb->v4lbuf.index = i;
298 pb->v4lbuf.type = capture_p.type;
299 pb->v4lbuf.memory = V4L2_MEMORY_DMABUF;
300 pb->v4lbuf.length = capture_p.plane_num;
301 pb->v4lbuf.m.planes = pb->v4lplane;
302 /* allocate DRM-GEM buffers */
303 pb->drm_frame = display_create_buffer(coded_w, coded_h,
304 (g_dw_mode == VDEC_DW_AFBC_ONLY)? FRAME_FMT_AFBC:FRAME_FMT_NV12,
305 capture_p.plane_num);
306 if (ret) {
307 printf("display_create_buffer %dth fail\n", i);
308 return 2;
309 }
310
311 ret = ioctl(video_fd, VIDIOC_QUERYBUF, &pb->v4lbuf);
312 if (ret) {
313 printf("VIDIOC_QUERYBUF %dth buf fail ret:%d\n", i, ret);
314 return 3;
315 }
316 ret = display_get_buffer_fds(pb->drm_frame, fd, 2);
317 if (ret) {
318 printf("display get %dth fds fail %d\n", i, ret);
319 return 4;
320 }
321 /* bind GEM-fd with V4L2 buffer */
322 for (j = 0; j < capture_p.plane_num; j++) {
323 pb->vaddr[j] = NULL;
324 pb->gem_fd[j] = fd[j];
325 pb->v4lbuf.m.planes[j].m.fd = pb->gem_fd[j];
326 }
327
328 ret = ioctl(video_fd, VIDIOC_QBUF, &capture_p.buf[i]->v4lbuf);
329 if (ret) {
330 printf("VIDIOC_QBUF %dth buf fail ret:%d\n", i, ret);
331 return 5;
332 }
333 capture_p.buf[i]->queued = true;
334 }
335 gettimeofday(&res_profile.buffer_done, NULL);
336
337 return 0;
338}
339
340static int destroy_capture_port(int fd) {
341 int i;
342 struct v4l2_requestbuffers req = {
343 .memory = V4L2_MEMORY_DMABUF,
344 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
345 .count = 0,
346 };
347 pthread_mutex_destroy(&capture_p.lock);
348 pthread_cond_destroy(&capture_p.wait);
349 ioctl(fd, VIDIOC_REQBUFS, &req);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700350 for (i = 0 ; i < req.count ; i++) {
351 struct frame_buffer *buf = capture_p.buf[i];
352 /* release GEM buf */
353 buf->drm_frame->destroy(buf->drm_frame);
Song Zhao1b237602020-02-13 10:58:57 -0800354 free(capture_p.buf[i]);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700355 }
Song Zhao1b237602020-02-13 10:58:57 -0800356 free(capture_p.buf);
357 return 0;
358}
359
360static void detect_res_change(struct v4l2_format *old, struct v4l2_format *new)
361{
362 if (old->fmt.pix_mp.width != new->fmt.pix_mp.width ||
363 old->fmt.pix_mp.height != new->fmt.pix_mp.height) {
364 printf("%dx%d --> %dx%d\n", old->fmt.pix_mp.width,
365 old->fmt.pix_mp.height, new->fmt.pix_mp.width,
366 new->fmt.pix_mp.height);
367 }
368}
369
370static void handle_res_change()
371{
372 int i, ret;
373 int free_cnt = 0, delay_cnt = 0;
374 struct v4l2_format out_fmt = { 0 };
375 struct v4l2_requestbuffers req = {
376 .memory = V4L2_MEMORY_DMABUF,
377 .type = capture_p.type,
378 .count = 0,
379 };
380
381 out_fmt.type = output_p.type;
382 ret = ioctl(video_fd, VIDIOC_G_FMT, &out_fmt);
383 if (ret) {
384 printf("output VIDIOC_G_FMT fail :%d\n",ret);
385 goto error;
386 }
387
388 detect_res_change(&output_p.sfmt, &out_fmt);
389
390 /* stop capture port */
391 ret = ioctl(video_fd, VIDIOC_STREAMOFF, &capture_p.type);
392 if (ret) {
393 printf("VIDIOC_STREAMOFF fail ret:%d\n",ret);
394 goto error;
395 }
396
397 pthread_mutex_lock(&res_lock);
398 /* return all DRM-GEM buffers */
399 ret = ioctl(video_fd, VIDIOC_REQBUFS, &req);
400 if (ret) {
401 printf("VIDIOC_REQBUFS fail ret:%d\n",ret);
402 pthread_mutex_unlock(&res_lock);
403 goto error;
404 }
405 for (i = 0 ; i < capture_p.buf_num; i++) {
406 if (capture_p.buf[i]->queued) {
407 struct drm_frame *drm_f = capture_p.buf[i]->drm_frame;
408
409 drm_f->destroy(drm_f);
410 free(capture_p.buf[i]);
411 free_cnt++;
412 } else {
413 capture_p.buf[i]->free_on_recycle = true;
414 delay_cnt++;
415 }
416 }
417 pthread_mutex_unlock(&res_lock);
418 free(capture_p.buf);
419 printf("f/d/total: (%d/%d/%d)\n", free_cnt, delay_cnt, capture_p.buf_num);
420
421 /* setup capture port again */
422 ret = setup_capture_port(video_fd);
423 if (ret) {
424 printf(" setup_capture_port fail ret:%d\n",ret);
425 goto error;
426 }
427
428 /* start capture again */
429 ret = ioctl(video_fd, VIDIOC_STREAMON, &capture_p.type);
430 if (ret) {
431 printf("VIDIOC_STREAMON fail ret:%d\n",ret);
432 goto error;
433 }
434 return;
435
436error:
437 printf("debug...\n");
438 while (1)
439 sleep(1);
440}
441
442static uint32_t v4l2_get_event(int fd)
443{
444 int ret;
445 struct v4l2_event evt = { 0 };
446
447 ret = ioctl(fd, VIDIOC_DQEVENT, &evt);
448 if (ret) {
449 printf("VIDIOC_DQEVENT fail, ret:%d\n", ret);
450 return 0;
451 }
452 return evt.type;
453}
454
455static void *dec_thread_func(void * arg) {
456 int ret = 0;
457 struct pollfd pfd = {
458 /* default blocking capture */
459 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
460 .fd = video_fd,
461 };
462 while (!quit_thread) {
463 struct v4l2_buffer buf;
464 struct v4l2_plane planes[2];
465
466 for (;;) {
467 ret = poll(&pfd, 1, 10);
468 if (ret > 0)
469 break;
470 if (quit_thread)
471 goto exit;
472 if (errno == EINTR)
473 continue;
474
475 }
476
477 /* error handling */
478 if (pfd.revents & POLLERR)
479 printf("POLLERR received\n");
480
481 /* res change */
482 if (pfd.revents & POLLPRI) {
483 uint32_t evt;
484 evt = v4l2_get_event(video_fd);
485 if (evt == V4L2_EVENT_SOURCE_CHANGE)
486 res_evt_pending = true;
487 else if (evt == V4L2_EVENT_EOS)
488 eos_evt_pending = true;
489 printf("res_evt_pending:%d eos_evt_pending:%d\n",
490 res_evt_pending, eos_evt_pending);
491 }
492
493
494
495 /* dqueue output buf */
496 if (pfd.revents & (POLLOUT | POLLWRNORM)) {
497 memset(&buf, 0, sizeof(buf));
498 memset(planes, 0, sizeof(planes));
Song Zhao6c7d1f82020-04-06 23:22:49 -0700499 buf.memory = sInMemMode;
Song Zhao1b237602020-02-13 10:58:57 -0800500 buf.type = output_p.type;
501 buf.length = 2;
502 buf.m.planes = planes;
503
504 ret = ioctl(video_fd, VIDIOC_DQBUF, &buf);
505 if (ret) {
506 printf("output VIDIOC_DQBUF fail %d\n", ret);
507 } else {
Song Zhao6c7d1f82020-04-06 23:22:49 -0700508 struct frame_buffer *fb = output_p.buf[buf.index];
Song Zhao1b237602020-02-13 10:58:57 -0800509#ifdef DEBUG_FRAME
510 printf("dqueue output %d\n", buf.index);
511#endif
512 pthread_mutex_lock(&output_p.lock);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700513 fb->queued = false;
Song Zhao1b237602020-02-13 10:58:57 -0800514 pthread_mutex_unlock(&output_p.lock);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700515 fb->used = 0;
Song Zhao1b237602020-02-13 10:58:57 -0800516 d_o_rec_num++;
Song Zhaoec315042020-06-12 00:51:42 -0700517#ifdef CONFIG_SECMEM
Song Zhao6c7d1f82020-04-06 23:22:49 -0700518 if (sInMemMode == V4L2_MEMORY_DMABUF) {
519 secmem_free(fb->smem);
520 }
Song Zhaoec315042020-06-12 00:51:42 -0700521#endif
Song Zhao1b237602020-02-13 10:58:57 -0800522 pthread_cond_signal(&output_p.wait);
523 }
524 }
525 /* dqueue capture buf */
526 if (pfd.revents & (POLLIN | POLLRDNORM)) {
527 memset(&buf, 0, sizeof(buf));
528 memset(planes, 0, sizeof(planes));
529 buf.memory = V4L2_MEMORY_DMABUF;
530 buf.type = capture_p.type;
531 buf.length = 2;
532 buf.m.planes = planes;
533
534 ret = ioctl(video_fd, VIDIOC_DQBUF, &buf);
535 if (ret) {
536 printf("capture VIDIOC_DQBUF fail %d\n", ret);
537 } else {
538#ifdef DEBUG_FRAME
539 printf("dqueue cap %d\n", buf.index);
540#endif
541 capture_p.buf[buf.index]->queued = false;
542 d_c_push_num++;
543 /* ignore res change for 1st frame */
544 if (d_c_push_num == 1 && res_evt_pending) {
545 printf("ignore res change for 1st frame\n");
546 res_evt_pending = false;
547 }
548 if (!(buf.flags & V4L2_BUF_FLAG_LAST)) {
549 struct drm_frame *drm_f = capture_p.buf[buf.index]->drm_frame;
550 /* display capture buf */
551 if (res_profile.res_change) {
552 res_profile.res_change = false;
553 gettimeofday(&res_profile.first_frame, NULL);
554 printf("--event to buffer done %dms--\n",
555 span(&res_profile.last_flag, &res_profile.buffer_done));
556 printf("--event to 1st frame %dms--\n",
557 span(&res_profile.last_flag, &res_profile.first_frame));
558 }
559 drm_f->pri_dec = capture_p.buf[buf.index];
560 display_engine_show(drm_f);
561 } else {
562 uint32_t evt = 0;
563 if (!res_evt_pending && !eos_evt_pending)
564 evt = v4l2_get_event(video_fd);
565
566 if (evt == V4L2_EVENT_SOURCE_CHANGE || res_evt_pending) {
567 printf("res changed\n");
568 res_evt_pending = false;
569 gettimeofday(&res_profile.last_flag, NULL);
570 res_profile.res_change = true;
571 /* this buffer will be freed in handle_res_change */
572 capture_p.buf[buf.index]->queued = true;
573 handle_res_change();
574 d_c_rec_num++;
575 continue;
576 } else if (evt == V4L2_EVENT_EOS || eos_evt_pending) {
577 printf("EOS received\n");
578 eos_received = true;
579 eos_evt_pending = false;
580 display_wait_for_display();
581 d_c_rec_num++;
582 dump_v4l2_decode_state();
583 decode_finish_cb();
584 break;
585 }
586 }
587 }
588 }
589 }
590
591exit:
592 /* stop output port */
593 ret = ioctl(video_fd, VIDIOC_STREAMOFF, &output_p.type);
594 if (ret) {
595 printf("VIDIOC_STREAMOFF fail ret:%d\n",ret);
596 }
597
598 /* stop capture port */
599 ret = ioctl(video_fd, VIDIOC_STREAMOFF, &capture_p.type);
600 if (ret) {
601 printf("VIDIOC_STREAMOFF fail ret:%d\n",ret);
602 }
603
604 return NULL;
605}
606
607static int config_decoder(int fd, enum vtype type)
608{
609 int ret = -1;
610 struct v4l2_streamparm para;
611 struct v4l2_event_subscription sub;
612 struct aml_dec_params *dec_p = (struct aml_dec_params *)para.parm.raw_data;
613
614 memset(&para, 0 , sizeof(para));
615 para.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
616 dec_p->parms_status = V4L2_CONFIG_PARM_DECODE_CFGINFO;
617 dec_p->cfg.double_write_mode = g_dw_mode;
618 /* number of extra buffer for display pipelien to run */
619 /* MPEG will use hardcoded size in driver */
620 if (type != VIDEO_TYPE_MPEG2)
621 dec_p->cfg.ref_buf_margin = 7;
622
623 //optional adjust dec_p->hdr for hdr support
624
625 if ((ret = ioctl(video_fd, VIDIOC_S_PARM, &para))) {
626 printf("VIDIOC_S_PARM fails ret:%d\n", ret);
627 return ret;
628 }
629
630 /* subscribe to resolution change and EOS event */
631 memset(&sub, 0, sizeof(sub));
632 sub.type = V4L2_EVENT_SOURCE_CHANGE;
633 ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
634 if (ret) {
635 printf("subscribe V4L2_EVENT_SOURCE_CHANGE fail\n");
636 return ret;
637 }
638
639 memset(&sub, 0, sizeof(sub));
640 sub.type = V4L2_EVENT_EOS;
641 ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
642 if (ret) {
643 printf("subscribe V4L2_EVENT_EOS fail\n");
644 return ret;
645 }
646 return 0;
647}
648
649#define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100)
650#define AML_V4L2_SET_DRMMODE (V4L2_CID_USER_AMLOGIC_BASE + 0)
651static int v4l2_dec_set_drmmode(bool drm_enable)
652{
653 int rc = 0;
654 struct v4l2_queryctrl queryctrl;
655 struct v4l2_control control;
656
657 memset (&queryctrl, 0, sizeof (queryctrl));
658 queryctrl.id = AML_V4L2_SET_DRMMODE;
659
660 if (-1 == ioctl (video_fd, VIDIOC_QUERYCTRL, &queryctrl)) {
661 printf ("AML_V4L2_SET_DRMMODE is not supported\n");
662 } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
663 printf ("AML_V4L2_SET_DRMMODE is disable\n");
664 } else {
665 memset (&control, 0, sizeof (control));
666 control.id = AML_V4L2_SET_DRMMODE;
667 control.value = drm_enable;
668
669 rc = ioctl (video_fd, VIDIOC_S_CTRL, &control);
670 if (rc) {
671 printf ("AML_V4L2_SET_DRMMODE fail\n");
672 }
673 }
674 return rc;
675}
676
Song Zhao6c7d1f82020-04-06 23:22:49 -0700677int v4l2_dec_init(enum vtype type, int secure, decode_finish_fn cb)
Song Zhao1b237602020-02-13 10:58:57 -0800678{
679 int ret = -1;
680 struct v4l2_capability cap;
681 struct v4l2_fmtdesc fdesc;
682 bool supported;
683
684 if (!cb)
685 return 1;
686 decode_finish_cb = cb;
687
Song Zhao6c7d1f82020-04-06 23:22:49 -0700688 if (secure) {
Song Zhaoec315042020-06-12 00:51:42 -0700689#ifdef CONFIG_SECMEM
Song Zhao6c7d1f82020-04-06 23:22:49 -0700690 sInMemMode = V4L2_MEMORY_DMABUF;
691 ret = secmem_init();
692 if (ret) {
693 printf("secmem_init fail %d\n",ret);
694 return 1;
695 }
Song Zhaoec315042020-06-12 00:51:42 -0700696#endif
Song Zhao6c7d1f82020-04-06 23:22:49 -0700697 } else
698 sInMemMode = V4L2_MEMORY_MMAP;
699
Song Zhao1b237602020-02-13 10:58:57 -0800700 /* check decoder mode */
701 if ((type == VIDEO_TYPE_H264 ||
702 type == VIDEO_TYPE_MPEG2) &&
703 g_dw_mode != 16) {
704 printf("mpeg2/h264 only support DW 16 mode\n");
705 goto error;
706 }
707
708 /* config sys nodes */
709 if (config_sys_node("/sys/module/amvdec_ports/parameters/multiplanar", "1")) {
710 printf("set multiplanar fails\n");
711 goto error;
712 }
Song Zhao33f4cc32020-05-02 22:13:24 -0700713 if (type == VIDEO_TYPE_VP9 && !secure) {
Song Zhao1b237602020-02-13 10:58:57 -0800714 if (config_sys_node("/sys/module/amvdec_ports/parameters/vp9_need_prefix", "1")) {
715 printf("set vp9_need_prefix fails\n");
716 goto error;
717 }
718 }
719 if (type == VIDEO_TYPE_MPEG2) {
720 //TODO: delete after ucode updated for mpeg2
721 if (config_sys_node("/sys/module/amvdec_ports/parameters/param_sets_from_ucode", "0")) {
722 printf("set param_sets_from_ucode 0 fails\n");
723 goto error;
724 }
725 }
726
727 pthread_mutex_init(&res_lock, NULL);
728 video_fd = open(video_dev_name, O_RDWR | O_NONBLOCK, 0);
729 if (video_fd < 0) {
730 printf("Unable to open video node: %s\n",
731 strerror(errno));
732 goto error;
733 }
734
735 if (type != VIDEO_TYPE_MPEG2) {
Song Zhao6c7d1f82020-04-06 23:22:49 -0700736 ret = v4l2_dec_set_drmmode(secure);
Song Zhao1b237602020-02-13 10:58:57 -0800737 if (ret) {
738 printf("aml_v4l2_dec_set_drmmode fail\n");
739 goto error;
740 }
741 }
742
743 if ((ret = ioctl(video_fd, VIDIOC_QUERYCAP, &cap))) {
744 printf("VIDIOC_QUERYCAP fails ret:%d\n", ret);
745 goto error;
746 }
747
748 if (!(cap.capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)) {
749 printf("V4L2_CAP_VIDEO_M2M_MPLANE fails\n");
750 goto error;
751 }
752 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
753 printf("V4L2_CAP_STREAMING fails\n");
754 goto error;
755 }
756
757 /* output fmt */
758 output_p.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
759 supported = false;
760 memset(&fdesc, 0, sizeof(fdesc));
761 fdesc.type = output_p.type;
762 for (;;) {
763 ret = ioctl(video_fd, VIDIOC_ENUM_FMT, &fdesc);
764 if (ret)
765 break;
766 if (v4l2_fourcc_to_vtype(fdesc.pixelformat) == type) {
767 supported = true;
768 output_p.pixelformat = fdesc.pixelformat;
769 break;
770 }
771 fdesc.index++;
772 }
773 if (!supported) {
774 printf("output format not supported:%d\n", type);
775 goto error;
776 }
777
778 if (config_decoder(video_fd, type)) {
779 printf("config_decoder error\n");
780 goto error;
781 }
782
783 memset(&output_p.sfmt, 0, sizeof(struct v4l2_format));
784 output_p.sfmt.type = output_p.type;
785 ret = ioctl(video_fd, VIDIOC_G_FMT, &output_p.sfmt);
786 if (ret) {
787 printf("VIDIOC_G_FMT fail\n");
788 goto error;
789 }
790
791 output_p.sfmt.fmt.pix_mp.pixelformat = output_p.pixelformat;
792 /* 4K frame should fit into 2M */
Song Zhao6c7d1f82020-04-06 23:22:49 -0700793 output_p.sfmt.fmt.pix_mp.plane_fmt[0].sizeimage = ES_BUF_SIZE;
Song Zhao1b237602020-02-13 10:58:57 -0800794 ret = ioctl(video_fd, VIDIOC_S_FMT, &output_p.sfmt);
795 if (ret) {
796 printf("VIDIOC_S_FMT 0x%x fail\n", output_p.pixelformat);
797 goto error;
798 }
799 output_p.plane_num = output_p.sfmt.fmt.pix_mp.num_planes;
800
801 /* capture fmt */
802 capture_p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
803 supported = false;
804 memset(&fdesc, 0, sizeof(fdesc));
805 fdesc.type = capture_p.type;
806 for (;;) {
807 ret = ioctl(video_fd, VIDIOC_ENUM_FMT, &fdesc);
808 if (ret)
809 break;
810 if ((fdesc.pixelformat == V4L2_PIX_FMT_NV12M &&
811 g_dw_mode != VDEC_DW_AFBC_ONLY) ||
812 (fdesc.pixelformat == V4L2_PIX_FMT_NV12 &&
813 g_dw_mode == VDEC_DW_AFBC_ONLY)) {
814 supported = true;
815 capture_p.pixelformat = fdesc.pixelformat;
816 break;
817 }
818 fdesc.index++;
819 }
820 if (!supported) {
821 printf("capture format not supported\n");
822 goto error;
823 }
824
825 /* setup output port */
826 ret = setup_output_port(video_fd);
827 if (ret) {
828 printf("setup_output_port fail\n");
829 goto error;
830 }
831
832 /* start output port */
833 ret = ioctl(video_fd, VIDIOC_STREAMON, &output_p.type);
834 if (ret) {
835 printf("VIDIOC_STREAMON fail ret:%d\n",ret);
836 goto error;
837 }
838
839 printf("output stream on\n");
840 return 0;
841
842error:
843 close(video_fd);
844 video_fd = 0;
845 return ret;
846}
847
848static int handle_first_frame()
849{
850 int ret;
851 /* Wait for 1st video ES data and setup capture port */
852
853 ret = setup_capture_port(video_fd);
854 if (ret) {
855 printf(" setup_capture_port fail ret:%d\n",ret);
856 goto error;
857 }
858
859 pthread_mutex_init(&capture_p.lock, NULL);
860 pthread_cond_init(&capture_p.wait, NULL);
861
862 /* start capture port */
863 ret = ioctl(video_fd, VIDIOC_STREAMON, &capture_p.type);
864 if (ret) {
865 printf("VIDIOC_STREAMON fail ret:%d\n",ret);
866 goto error;
867 }
868 printf("capture stream on\n");
869
870 if (pthread_create(&dec_thread, NULL, dec_thread_func, NULL)) {
871 printf("dec thread fail\n");
872 return -1;
873 }
874 return 0;
875error:
876 printf("handle_first_frame fatal\n");
877 while (1) sleep(1);
878 exit(1);
879}
880
881int v4l2_dec_destroy()
882{
883 quit_thread = true;
884 pthread_cond_signal(&output_p.wait);
885 pthread_join(dec_thread, NULL);
886 destroy_output_port(video_fd);
887 destroy_capture_port(video_fd);
888 get_1st_data = false;
889 pthread_mutex_destroy(&res_lock);
890 close(video_fd);
Song Zhaoec315042020-06-12 00:51:42 -0700891#ifdef CONFIG_SECMEM
Song Zhao6c7d1f82020-04-06 23:22:49 -0700892 secmem_destroy();
Song Zhaoec315042020-06-12 00:51:42 -0700893#endif
Song Zhao6c7d1f82020-04-06 23:22:49 -0700894 if (es_buf)
895 free(es_buf);
Song Zhao1b237602020-02-13 10:58:57 -0800896 return 0;
897}
898
899static int get_free_output_buf()
900{
901 int i;
902 pthread_mutex_lock(&output_p.lock);
903 do {
904 for (i = 0; i < output_p.buf_num; i++) {
905 if (!output_p.buf[i]->queued) {
906 break;
907 }
908 }
909
910 if (i == output_p.buf_num) {
911 pthread_cond_wait(&output_p.wait, &output_p.lock);
912 if (quit_thread)
913 break;
914 } else {
915 break;
916 }
917 } while (1);
918 pthread_mutex_unlock(&output_p.lock);
919
920 if (i == output_p.buf_num)
921 return -1;
922
923 return i;
924}
925
926#if 0
927static void dump(const char* path, const uint8_t *data, int size) {
928 FILE* fd = fopen(path, "ab");
929 if (!fd)
930 return;
931 fwrite(data, 1, size, fd);
932 fclose(fd);
933}
934#endif
935
936int v4l2_dec_write_es(const uint8_t *data, int size)
937{
938 struct frame_buffer *p;
939
940 if (cur_output_index == -1)
941 cur_output_index = get_free_output_buf();
942
943 if (cur_output_index < 0) {
944 printf("%s %d can not get output buf\n", __func__, __LINE__);
945 return 0;
946 }
947
948 p = output_p.buf[cur_output_index];
Song Zhao6c7d1f82020-04-06 23:22:49 -0700949 if ((sInMemMode == V4L2_MEMORY_MMAP &&
950 (p->used + size) > p->v4lplane[0].length) ||
951 (sInMemMode == V4L2_MEMORY_DMABUF &&
952 (p->used + size) > ES_BUF_SIZE)) {
953 printf("fatal frame too big %d\n",
954 size + p->used);
Song Zhao1b237602020-02-13 10:58:57 -0800955 return 0;
956 }
Song Zhao6c7d1f82020-04-06 23:22:49 -0700957
958 if (sInMemMode == V4L2_MEMORY_MMAP)
959 memcpy(p->vaddr[0] + p->used, data, size);
960 else
961 memcpy(es_buf + p->used, data, size);
962
Song Zhao1b237602020-02-13 10:58:57 -0800963 p->used += size;
964
965#ifdef DEBUG_FRAME
966 int i;
967 for (i = 0 ; i < size ; i++)
968 frame_checksum += data[i];
969#endif
970
971 //dump("/data/es.h265", data, size);
972 //
973 return size;
974}
975
Song Zhaof781ce52020-06-10 23:44:16 -0700976int v4l2_dec_frame_done(int64_t pts)
Song Zhao1b237602020-02-13 10:58:57 -0800977{
978 int ret;
979 struct frame_buffer *p;
980
981 if (quit_thread)
982 return 0;
983
984 if (cur_output_index < 0 || cur_output_index >= output_p.buf_num) {
985 printf("BUG %s %d idx:%d\n", __func__, __LINE__, cur_output_index);
986 return 0;
987 }
988 p = output_p.buf[cur_output_index];
Song Zhaoec315042020-06-12 00:51:42 -0700989#ifdef CONFIG_SECMEM
Song Zhao6c7d1f82020-04-06 23:22:49 -0700990 if (sInMemMode == V4L2_MEMORY_DMABUF) {
Song Zhao33f4cc32020-05-02 22:13:24 -0700991 int frame_size = p->used;
992 int offset = 0;
993 struct vp9_superframe_split s;
994
995 if (output_p.pixelformat == V4L2_PIX_FMT_VP9) {
996 s.data = es_buf;
997 s.data_size = p->used;
998 ret = vp9_superframe_split_filter(&s);
999 if (ret) {
1000 printf("parse vp9 superframe fail\n");
1001 return 0;
1002 }
1003 frame_size = s.size + s.nb_frames * 16;
1004 }
1005
1006 p->smem = secmem_alloc(frame_size);
Song Zhao6c7d1f82020-04-06 23:22:49 -07001007 if (!p->smem) {
1008 printf("%s %d oom:%d\n", __func__, __LINE__, p->used);
1009 return 0;
1010 }
Song Zhao33f4cc32020-05-02 22:13:24 -07001011
1012 /* copy to secmem */
1013 if (output_p.pixelformat == V4L2_PIX_FMT_VP9) {
1014 int stream_offset = s.size;
1015 offset = frame_size;
1016 for (int i = s.nb_frames; i > 0; i--) {
1017 uint8_t header[16];
1018 uint32_t sub_size = s.sizes[i - 1];
1019
1020 /* frame body */
1021 offset -= sub_size;
1022 stream_offset -= sub_size;
1023 secmem_fill(p->smem, es_buf + stream_offset, offset, sub_size);
1024
1025 /* prepend header */
1026 offset -= 16;
1027 fill_vp9_header(header, sub_size);
1028 secmem_fill(p->smem, header, offset, 16);
1029 }
1030 } else
1031 secmem_fill(p->smem, es_buf, offset, p->used);
1032
Song Zhao6c7d1f82020-04-06 23:22:49 -07001033 p->v4lbuf.m.planes[0].m.fd = p->smem->fd;
Song Zhao33f4cc32020-05-02 22:13:24 -07001034 p->v4lbuf.m.planes[0].length = frame_size;
Song Zhao6c7d1f82020-04-06 23:22:49 -07001035 p->v4lbuf.m.planes[0].data_offset = 0;
1036 }
Song Zhaoec315042020-06-12 00:51:42 -07001037#endif
Song Zhao1b237602020-02-13 10:58:57 -08001038 p->v4lbuf.m.planes[0].bytesused = p->used;
Song Zhaof781ce52020-06-10 23:44:16 -07001039
1040 /* convert from ns to timeval */
1041 p->v4lbuf.timestamp.tv_sec = pts / DMX_SECOND;
1042 p->v4lbuf.timestamp.tv_usec = pts % DMX_SECOND;
1043
Song Zhao1b237602020-02-13 10:58:57 -08001044 pthread_mutex_lock(&output_p.lock);
1045 p->queued = true;
1046 pthread_mutex_unlock(&output_p.lock);
1047 ret = ioctl(video_fd, VIDIOC_QBUF, &p->v4lbuf);
1048 if (ret) {
1049 printf("write es VIDIOC_QBUF %dth buf fail ret:%d\n",
1050 cur_output_index, ret);
1051 return 0;
1052 }
1053#ifdef DEBUG_FRAME
1054 printf("%s queue output %d frame_checksum:%x\n", __func__, cur_output_index, frame_checksum);
1055 frame_checksum = 0;
1056#endif
1057 d_o_push_num++;
1058 cur_output_index = -1;
1059 /* can setup capture port now */
1060 if (!get_1st_data) {
1061 printf("%s 1st frame done\n", __func__);
1062 get_1st_data = true;
1063 handle_first_frame();
1064 } else {
1065 }
1066 return ret;
1067}
1068
1069int capture_buffer_recycle(void* handle)
1070{
1071 int ret = 0;
1072 struct frame_buffer *frame = handle;
1073
1074 d_c_rec_num++;
1075 pthread_mutex_lock(&res_lock);
1076 if (frame->free_on_recycle) {
1077 printf("free index:%d\n", frame->v4lbuf.index);
1078 frame->drm_frame->destroy(frame->drm_frame);
1079 free(frame);
1080 goto exit;
1081 }
1082
1083 if (eos_received)
1084 goto exit;
1085
1086 ret = ioctl(video_fd, VIDIOC_QBUF, &frame->v4lbuf);
1087 if (ret) {
1088 printf("VIDIOC_QBUF %dth buf fail ret:%d\n", frame->v4lbuf.index, ret);
1089 goto exit;
1090 } else {
1091#ifdef DEBUG_FRAME
1092 printf("queue cap %d\n", frame->v4lbuf.index);
1093#endif
1094 frame->queued = true;
1095 }
1096exit:
1097 pthread_mutex_unlock(&res_lock);
1098 return ret;
1099}
1100
1101int v4l2_dec_eos()
1102{
1103 int ret;
1104 struct v4l2_decoder_cmd cmd = {
1105 .cmd = V4L2_DEC_CMD_STOP,
1106 .flags = 0,
1107 };
1108
1109 printf("%s EOS received\n", __func__);
1110 /* flush decoder */
1111 ret = ioctl(video_fd, VIDIOC_DECODER_CMD, &cmd);
1112 if (ret)
1113 printf("V4L2_DEC_CMD_STOP output fail ret:%d\n",ret);
1114
1115 return ret;
1116}
1117
1118void dump_v4l2_decode_state()
1119{
1120 printf("-----------------------\n");
1121 printf("output port: push(%d) pop(%d)\n", d_o_push_num, d_o_rec_num);
1122 printf("capture port: push(%d) pop(%d)\n", d_c_push_num, d_c_rec_num);
1123 printf("-----------------------\n");
1124}