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