blob: c15441eb112abdff7e81ae2806f79499090c65cd [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 Zhao6c7d1f82020-04-06 23:22:49 -070029#include "secmem.h"
Song Zhao1b237602020-02-13 10:58:57 -080030
31static const char* video_dev_name = "/dev/video26";
32static int video_fd;
33static bool get_1st_data = false;
34static int cur_output_index = -1;
35static decode_finish_fn decode_finish_cb;
36static bool res_evt_pending;
37static bool eos_evt_pending;
38static bool eos_received;
39extern int g_dw_mode;
40static pthread_mutex_t res_lock;
Song Zhao6c7d1f82020-04-06 23:22:49 -070041static enum v4l2_memory sInMemMode;
42static uint8_t* es_buf;
Song Zhao1b237602020-02-13 10:58:57 -080043//#define DEBUG_FRAME
44#ifdef DEBUG_FRAME
45static int frame_checksum;
46#endif
Song Zhao6c7d1f82020-04-06 23:22:49 -070047#define ES_BUF_SIZE (2*1024*1024)
Song Zhao1b237602020-02-13 10:58:57 -080048
49static pthread_t dec_thread;
50bool quit_thread;
51extern int config_sys_node(const char* path, const char* value);
52extern int span(struct timeval* t1, struct timeval* t2);
53
54struct frame_buffer {
55 struct v4l2_buffer v4lbuf;
56 struct v4l2_plane v4lplane[2];
57 uint8_t *vaddr[2];
58 int gem_fd[2];
59 bool queued;
60
61 /* output only */
62 uint32_t used;
Song Zhao6c7d1f82020-04-06 23:22:49 -070063 struct secmem* smem;
64
Song Zhao1b237602020-02-13 10:58:57 -080065 /* capture only */
66 bool free_on_recycle;
67 struct drm_frame *drm_frame;
68};
69
70struct port_config {
71 enum v4l2_buf_type type;
72 uint32_t pixelformat;
73 struct v4l2_format sfmt;
74 int buf_num;
75 int plane_num;
76 struct frame_buffer** buf;
77 pthread_mutex_t lock;
78 pthread_cond_t wait;
79};
80
81#define OUTPUT_BUF_CNT 4
82static struct port_config output_p;
83static struct port_config capture_p;
84
85static int d_o_push_num;
86static int d_o_rec_num;
87static int d_c_push_num;
88static int d_c_rec_num;
89
90struct profile {
91 bool res_change;
92 struct timeval last_flag;
93 struct timeval buffer_done;
94 struct timeval first_frame;
95};
96static struct profile res_profile;
97
98static enum vtype v4l2_fourcc_to_vtype(uint32_t fourcc) {
99 switch (fourcc) {
100 case V4L2_PIX_FMT_H264:
101 return VIDEO_TYPE_H264;
102 case V4L2_PIX_FMT_HEVC:
103 return VIDEO_TYPE_H265;
104 case V4L2_PIX_FMT_VP9:
105 return VIDEO_TYPE_VP9;
106 case V4L2_PIX_FMT_MPEG2:
107 return VIDEO_TYPE_MPEG2;
108 }
109 return VIDEO_TYPE_MAX;
110}
111
112static uint32_t get_driver_min_buffers (int fd, bool capture_port)
113{
114 struct v4l2_control control = { 0, };
115
116 if (!capture_port)
117 control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
118 else
119 control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
120
121 if (!ioctl(fd, VIDIOC_G_CTRL, &control))
122 return control.value;
123
124 return 0;
125}
126
127static int setup_output_port(int fd)
128{
129 int i,ret;
130 struct v4l2_requestbuffers req;
131
132 req.count = get_driver_min_buffers(fd, false);
133 if (!req.count) {
134 printf("fail to get min buffers for output, use default\n");
135 req.count = OUTPUT_BUF_CNT;
136 }
137
Song Zhao6c7d1f82020-04-06 23:22:49 -0700138 req.memory = sInMemMode;
Song Zhao1b237602020-02-13 10:58:57 -0800139 req.type = output_p.type;
140
141 ret = ioctl(fd, VIDIOC_REQBUFS, &req);
142 if (ret < 0) {
143 printf("output VIDIOC_REQBUFS fail ret:%d\n", ret);
144 return 1;
145 }
146 output_p.buf_num = req.count;
147 printf("output gets %d buf\n", req.count);
148
149 output_p.buf = calloc(req.count, sizeof(struct frame_buffer *));
150 if (!output_p.buf) {
151 printf("%d oom\n", __LINE__);
152 return 2;
153 }
154 for (i = 0 ; i < req.count ; i++)
155 output_p.buf[i] = calloc(1, sizeof(struct frame_buffer));
156
157 for (i = 0; i < req.count; i++) {
158 int j;
159 struct frame_buffer* pb = output_p.buf[i];
160 pb->v4lbuf.index = i;
161 pb->v4lbuf.type = output_p.type;
Song Zhao6c7d1f82020-04-06 23:22:49 -0700162 pb->v4lbuf.memory = sInMemMode;
Song Zhao1b237602020-02-13 10:58:57 -0800163 pb->v4lbuf.length = output_p.plane_num;
164 pb->v4lbuf.m.planes = pb->v4lplane;
165
166 ret = ioctl(fd, VIDIOC_QUERYBUF, &pb->v4lbuf);
167 if (ret) {
168 printf("VIDIOC_QUERYBUF %dth buf fail ret:%d\n", i, ret);
169 return 3;
170 }
Song Zhao6c7d1f82020-04-06 23:22:49 -0700171
172 if (sInMemMode != V4L2_MEMORY_MMAP)
173 continue;
Song Zhao1b237602020-02-13 10:58:57 -0800174 for (j = 0; j < output_p.plane_num; j++) {
175 void *vaddr;
176 vaddr = mmap(NULL, pb->v4lplane[j].length,
177 PROT_READ | PROT_WRITE, MAP_SHARED,
178 fd, pb->v4lplane[j].m.mem_offset);
179 if (vaddr == MAP_FAILED) {
180 printf("%s mmap faild len:%d offset:%x\n", __func__,
181 pb->v4lplane[j].length, pb->v4lplane[j].m.mem_offset);
182 return 4;
183 }
184 pb->vaddr[j] = (uint8_t *)vaddr;
185 }
186
187 }
188
189 pthread_mutex_init(&output_p.lock, NULL);
190 pthread_cond_init(&output_p.wait, NULL);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700191
192 if (sInMemMode == V4L2_MEMORY_DMABUF) {
193 es_buf = malloc(ES_BUF_SIZE);
194 if (!es_buf) {
195 printf("%d OOM\n", __LINE__);
196 return 5;
197 }
198 }
Song Zhao1b237602020-02-13 10:58:57 -0800199 return 0;
200}
201
202static int destroy_output_port(int fd) {
203 int i;
204 struct v4l2_requestbuffers req = {
Song Zhao6c7d1f82020-04-06 23:22:49 -0700205 .memory = sInMemMode,
Song Zhao1b237602020-02-13 10:58:57 -0800206 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
207 .count = 0,
208 };
209 pthread_mutex_destroy(&output_p.lock);
210 pthread_cond_destroy(&output_p.wait);
211 ioctl(fd, VIDIOC_REQBUFS, &req);
212 for (i = 0 ; i < req.count ; i++) {
213 struct frame_buffer *buf = output_p.buf[i];
214
Song Zhao6c7d1f82020-04-06 23:22:49 -0700215 if (sInMemMode == V4L2_MEMORY_DMABUF)
216 secmem_free(buf->smem);
217
Song Zhao1b237602020-02-13 10:58:57 -0800218 free(buf);
219 }
220 free(output_p.buf);
221 return 0;
222}
223
224static int setup_capture_port(int fd)
225{
226 int i,ret;
227 uint32_t coded_w, coded_h;
228 struct v4l2_requestbuffers req;
229
230
231 /* coded size should be ready now */
232 memset(&capture_p.sfmt, 0, sizeof(struct v4l2_format));
233 capture_p.sfmt.type = capture_p.type;
234 ret = ioctl(video_fd, VIDIOC_G_FMT, &capture_p.sfmt);
235 if (ret) {
236 printf("%d VIDIOC_G_FMT fail :%d\n", __LINE__, ret);
237 return -1;
238 }
239 coded_w = capture_p.sfmt.fmt.pix_mp.width;
240 coded_h = capture_p.sfmt.fmt.pix_mp.height;
241 printf("capture port (%dx%d)\n", coded_w, coded_h);
242
243 if (g_dw_mode != VDEC_DW_AFBC_ONLY)
244 capture_p.sfmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
245 else
246 capture_p.sfmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
247 ret = ioctl(video_fd, VIDIOC_S_FMT, &capture_p.sfmt);
248 if (ret) {
249 printf("VIDIOC_S_FMT fail %d\n", ret);
250 return -1;
251 }
252 printf("set capture port to %s\n",
253 (g_dw_mode == VDEC_DW_AFBC_ONLY)?"NV12":"NV12M");
254 capture_p.plane_num = capture_p.sfmt.fmt.pix_mp.num_planes;
255 printf("number of capture plane: %d\n", capture_p.plane_num);
256
257 memset(&req, 0 , sizeof(req));
258 req.memory = V4L2_MEMORY_DMABUF;
259 req.type = capture_p.type;
260 req.count = get_driver_min_buffers(fd, true);
261 if (!req.count) {
262 printf("get min buffers fail\n");
263 return -1;
264 }
265
266 printf("req capture count:%d\n", req.count);
267 ret = ioctl(fd, VIDIOC_REQBUFS, &req);
268 if (ret < 0) {
269 printf("capture VIDIOC_REQBUFS fail ret:%d\n", ret);
270 return 1;
271 }
272 capture_p.buf_num = req.count;
273 printf("capture gets %d buf\n", req.count);
274
275 capture_p.buf = calloc(req.count, sizeof(struct frame_buffer *));
276 if (!capture_p.buf) {
277 printf("%d oom\n", __LINE__);
278 return 2;
279 }
280 for (i = 0 ; i < req.count ; i++) {
281 capture_p.buf[i] = calloc(1, sizeof(struct frame_buffer));
282 if (!capture_p.buf[i]) {
283 printf("%d oom\n", __LINE__);
284 return 2;
285 }
286 }
287
288 for (i = 0; i < req.count; i++) {
289 struct frame_buffer* pb = capture_p.buf[i];
290 int fd[4] = {0}, j;
291
292 pb->v4lbuf.index = i;
293 pb->v4lbuf.type = capture_p.type;
294 pb->v4lbuf.memory = V4L2_MEMORY_DMABUF;
295 pb->v4lbuf.length = capture_p.plane_num;
296 pb->v4lbuf.m.planes = pb->v4lplane;
297 /* allocate DRM-GEM buffers */
298 pb->drm_frame = display_create_buffer(coded_w, coded_h,
299 (g_dw_mode == VDEC_DW_AFBC_ONLY)? FRAME_FMT_AFBC:FRAME_FMT_NV12,
300 capture_p.plane_num);
301 if (ret) {
302 printf("display_create_buffer %dth fail\n", i);
303 return 2;
304 }
305
306 ret = ioctl(video_fd, VIDIOC_QUERYBUF, &pb->v4lbuf);
307 if (ret) {
308 printf("VIDIOC_QUERYBUF %dth buf fail ret:%d\n", i, ret);
309 return 3;
310 }
311 ret = display_get_buffer_fds(pb->drm_frame, fd, 2);
312 if (ret) {
313 printf("display get %dth fds fail %d\n", i, ret);
314 return 4;
315 }
316 /* bind GEM-fd with V4L2 buffer */
317 for (j = 0; j < capture_p.plane_num; j++) {
318 pb->vaddr[j] = NULL;
319 pb->gem_fd[j] = fd[j];
320 pb->v4lbuf.m.planes[j].m.fd = pb->gem_fd[j];
321 }
322
323 ret = ioctl(video_fd, VIDIOC_QBUF, &capture_p.buf[i]->v4lbuf);
324 if (ret) {
325 printf("VIDIOC_QBUF %dth buf fail ret:%d\n", i, ret);
326 return 5;
327 }
328 capture_p.buf[i]->queued = true;
329 }
330 gettimeofday(&res_profile.buffer_done, NULL);
331
332 return 0;
333}
334
335static int destroy_capture_port(int fd) {
336 int i;
337 struct v4l2_requestbuffers req = {
338 .memory = V4L2_MEMORY_DMABUF,
339 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
340 .count = 0,
341 };
342 pthread_mutex_destroy(&capture_p.lock);
343 pthread_cond_destroy(&capture_p.wait);
344 ioctl(fd, VIDIOC_REQBUFS, &req);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700345 for (i = 0 ; i < req.count ; i++) {
346 struct frame_buffer *buf = capture_p.buf[i];
347 /* release GEM buf */
348 buf->drm_frame->destroy(buf->drm_frame);
Song Zhao1b237602020-02-13 10:58:57 -0800349 free(capture_p.buf[i]);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700350 }
Song Zhao1b237602020-02-13 10:58:57 -0800351 free(capture_p.buf);
352 return 0;
353}
354
355static void detect_res_change(struct v4l2_format *old, struct v4l2_format *new)
356{
357 if (old->fmt.pix_mp.width != new->fmt.pix_mp.width ||
358 old->fmt.pix_mp.height != new->fmt.pix_mp.height) {
359 printf("%dx%d --> %dx%d\n", old->fmt.pix_mp.width,
360 old->fmt.pix_mp.height, new->fmt.pix_mp.width,
361 new->fmt.pix_mp.height);
362 }
363}
364
365static void handle_res_change()
366{
367 int i, ret;
368 int free_cnt = 0, delay_cnt = 0;
369 struct v4l2_format out_fmt = { 0 };
370 struct v4l2_requestbuffers req = {
371 .memory = V4L2_MEMORY_DMABUF,
372 .type = capture_p.type,
373 .count = 0,
374 };
375
376 out_fmt.type = output_p.type;
377 ret = ioctl(video_fd, VIDIOC_G_FMT, &out_fmt);
378 if (ret) {
379 printf("output VIDIOC_G_FMT fail :%d\n",ret);
380 goto error;
381 }
382
383 detect_res_change(&output_p.sfmt, &out_fmt);
384
385 /* stop capture port */
386 ret = ioctl(video_fd, VIDIOC_STREAMOFF, &capture_p.type);
387 if (ret) {
388 printf("VIDIOC_STREAMOFF fail ret:%d\n",ret);
389 goto error;
390 }
391
392 pthread_mutex_lock(&res_lock);
393 /* return all DRM-GEM buffers */
394 ret = ioctl(video_fd, VIDIOC_REQBUFS, &req);
395 if (ret) {
396 printf("VIDIOC_REQBUFS fail ret:%d\n",ret);
397 pthread_mutex_unlock(&res_lock);
398 goto error;
399 }
400 for (i = 0 ; i < capture_p.buf_num; i++) {
401 if (capture_p.buf[i]->queued) {
402 struct drm_frame *drm_f = capture_p.buf[i]->drm_frame;
403
404 drm_f->destroy(drm_f);
405 free(capture_p.buf[i]);
406 free_cnt++;
407 } else {
408 capture_p.buf[i]->free_on_recycle = true;
409 delay_cnt++;
410 }
411 }
412 pthread_mutex_unlock(&res_lock);
413 free(capture_p.buf);
414 printf("f/d/total: (%d/%d/%d)\n", free_cnt, delay_cnt, capture_p.buf_num);
415
416 /* setup capture port again */
417 ret = setup_capture_port(video_fd);
418 if (ret) {
419 printf(" setup_capture_port fail ret:%d\n",ret);
420 goto error;
421 }
422
423 /* start capture again */
424 ret = ioctl(video_fd, VIDIOC_STREAMON, &capture_p.type);
425 if (ret) {
426 printf("VIDIOC_STREAMON fail ret:%d\n",ret);
427 goto error;
428 }
429 return;
430
431error:
432 printf("debug...\n");
433 while (1)
434 sleep(1);
435}
436
437static uint32_t v4l2_get_event(int fd)
438{
439 int ret;
440 struct v4l2_event evt = { 0 };
441
442 ret = ioctl(fd, VIDIOC_DQEVENT, &evt);
443 if (ret) {
444 printf("VIDIOC_DQEVENT fail, ret:%d\n", ret);
445 return 0;
446 }
447 return evt.type;
448}
449
450static void *dec_thread_func(void * arg) {
451 int ret = 0;
452 struct pollfd pfd = {
453 /* default blocking capture */
454 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
455 .fd = video_fd,
456 };
457 while (!quit_thread) {
458 struct v4l2_buffer buf;
459 struct v4l2_plane planes[2];
460
461 for (;;) {
462 ret = poll(&pfd, 1, 10);
463 if (ret > 0)
464 break;
465 if (quit_thread)
466 goto exit;
467 if (errno == EINTR)
468 continue;
469
470 }
471
472 /* error handling */
473 if (pfd.revents & POLLERR)
474 printf("POLLERR received\n");
475
476 /* res change */
477 if (pfd.revents & POLLPRI) {
478 uint32_t evt;
479 evt = v4l2_get_event(video_fd);
480 if (evt == V4L2_EVENT_SOURCE_CHANGE)
481 res_evt_pending = true;
482 else if (evt == V4L2_EVENT_EOS)
483 eos_evt_pending = true;
484 printf("res_evt_pending:%d eos_evt_pending:%d\n",
485 res_evt_pending, eos_evt_pending);
486 }
487
488
489
490 /* dqueue output buf */
491 if (pfd.revents & (POLLOUT | POLLWRNORM)) {
492 memset(&buf, 0, sizeof(buf));
493 memset(planes, 0, sizeof(planes));
Song Zhao6c7d1f82020-04-06 23:22:49 -0700494 buf.memory = sInMemMode;
Song Zhao1b237602020-02-13 10:58:57 -0800495 buf.type = output_p.type;
496 buf.length = 2;
497 buf.m.planes = planes;
498
499 ret = ioctl(video_fd, VIDIOC_DQBUF, &buf);
500 if (ret) {
501 printf("output VIDIOC_DQBUF fail %d\n", ret);
502 } else {
Song Zhao6c7d1f82020-04-06 23:22:49 -0700503 struct frame_buffer *fb = output_p.buf[buf.index];
Song Zhao1b237602020-02-13 10:58:57 -0800504#ifdef DEBUG_FRAME
505 printf("dqueue output %d\n", buf.index);
506#endif
507 pthread_mutex_lock(&output_p.lock);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700508 fb->queued = false;
Song Zhao1b237602020-02-13 10:58:57 -0800509 pthread_mutex_unlock(&output_p.lock);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700510 fb->used = 0;
Song Zhao1b237602020-02-13 10:58:57 -0800511 d_o_rec_num++;
Song Zhao6c7d1f82020-04-06 23:22:49 -0700512 if (sInMemMode == V4L2_MEMORY_DMABUF) {
513 secmem_free(fb->smem);
514 }
Song Zhao1b237602020-02-13 10:58:57 -0800515 pthread_cond_signal(&output_p.wait);
516 }
517 }
518 /* dqueue capture buf */
519 if (pfd.revents & (POLLIN | POLLRDNORM)) {
520 memset(&buf, 0, sizeof(buf));
521 memset(planes, 0, sizeof(planes));
522 buf.memory = V4L2_MEMORY_DMABUF;
523 buf.type = capture_p.type;
524 buf.length = 2;
525 buf.m.planes = planes;
526
527 ret = ioctl(video_fd, VIDIOC_DQBUF, &buf);
528 if (ret) {
529 printf("capture VIDIOC_DQBUF fail %d\n", ret);
530 } else {
531#ifdef DEBUG_FRAME
532 printf("dqueue cap %d\n", buf.index);
533#endif
534 capture_p.buf[buf.index]->queued = false;
535 d_c_push_num++;
536 /* ignore res change for 1st frame */
537 if (d_c_push_num == 1 && res_evt_pending) {
538 printf("ignore res change for 1st frame\n");
539 res_evt_pending = false;
540 }
541 if (!(buf.flags & V4L2_BUF_FLAG_LAST)) {
542 struct drm_frame *drm_f = capture_p.buf[buf.index]->drm_frame;
543 /* display capture buf */
544 if (res_profile.res_change) {
545 res_profile.res_change = false;
546 gettimeofday(&res_profile.first_frame, NULL);
547 printf("--event to buffer done %dms--\n",
548 span(&res_profile.last_flag, &res_profile.buffer_done));
549 printf("--event to 1st frame %dms--\n",
550 span(&res_profile.last_flag, &res_profile.first_frame));
551 }
552 drm_f->pri_dec = capture_p.buf[buf.index];
553 display_engine_show(drm_f);
554 } else {
555 uint32_t evt = 0;
556 if (!res_evt_pending && !eos_evt_pending)
557 evt = v4l2_get_event(video_fd);
558
559 if (evt == V4L2_EVENT_SOURCE_CHANGE || res_evt_pending) {
560 printf("res changed\n");
561 res_evt_pending = false;
562 gettimeofday(&res_profile.last_flag, NULL);
563 res_profile.res_change = true;
564 /* this buffer will be freed in handle_res_change */
565 capture_p.buf[buf.index]->queued = true;
566 handle_res_change();
567 d_c_rec_num++;
568 continue;
569 } else if (evt == V4L2_EVENT_EOS || eos_evt_pending) {
570 printf("EOS received\n");
571 eos_received = true;
572 eos_evt_pending = false;
573 display_wait_for_display();
574 d_c_rec_num++;
575 dump_v4l2_decode_state();
576 decode_finish_cb();
577 break;
578 }
579 }
580 }
581 }
582 }
583
584exit:
585 /* stop output port */
586 ret = ioctl(video_fd, VIDIOC_STREAMOFF, &output_p.type);
587 if (ret) {
588 printf("VIDIOC_STREAMOFF fail ret:%d\n",ret);
589 }
590
591 /* stop capture port */
592 ret = ioctl(video_fd, VIDIOC_STREAMOFF, &capture_p.type);
593 if (ret) {
594 printf("VIDIOC_STREAMOFF fail ret:%d\n",ret);
595 }
596
597 return NULL;
598}
599
600static int config_decoder(int fd, enum vtype type)
601{
602 int ret = -1;
603 struct v4l2_streamparm para;
604 struct v4l2_event_subscription sub;
605 struct aml_dec_params *dec_p = (struct aml_dec_params *)para.parm.raw_data;
606
607 memset(&para, 0 , sizeof(para));
608 para.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
609 dec_p->parms_status = V4L2_CONFIG_PARM_DECODE_CFGINFO;
610 dec_p->cfg.double_write_mode = g_dw_mode;
611 /* number of extra buffer for display pipelien to run */
612 /* MPEG will use hardcoded size in driver */
613 if (type != VIDEO_TYPE_MPEG2)
614 dec_p->cfg.ref_buf_margin = 7;
615
616 //optional adjust dec_p->hdr for hdr support
617
618 if ((ret = ioctl(video_fd, VIDIOC_S_PARM, &para))) {
619 printf("VIDIOC_S_PARM fails ret:%d\n", ret);
620 return ret;
621 }
622
623 /* subscribe to resolution change and EOS event */
624 memset(&sub, 0, sizeof(sub));
625 sub.type = V4L2_EVENT_SOURCE_CHANGE;
626 ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
627 if (ret) {
628 printf("subscribe V4L2_EVENT_SOURCE_CHANGE fail\n");
629 return ret;
630 }
631
632 memset(&sub, 0, sizeof(sub));
633 sub.type = V4L2_EVENT_EOS;
634 ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
635 if (ret) {
636 printf("subscribe V4L2_EVENT_EOS fail\n");
637 return ret;
638 }
639 return 0;
640}
641
642#define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100)
643#define AML_V4L2_SET_DRMMODE (V4L2_CID_USER_AMLOGIC_BASE + 0)
644static int v4l2_dec_set_drmmode(bool drm_enable)
645{
646 int rc = 0;
647 struct v4l2_queryctrl queryctrl;
648 struct v4l2_control control;
649
650 memset (&queryctrl, 0, sizeof (queryctrl));
651 queryctrl.id = AML_V4L2_SET_DRMMODE;
652
653 if (-1 == ioctl (video_fd, VIDIOC_QUERYCTRL, &queryctrl)) {
654 printf ("AML_V4L2_SET_DRMMODE is not supported\n");
655 } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
656 printf ("AML_V4L2_SET_DRMMODE is disable\n");
657 } else {
658 memset (&control, 0, sizeof (control));
659 control.id = AML_V4L2_SET_DRMMODE;
660 control.value = drm_enable;
661
662 rc = ioctl (video_fd, VIDIOC_S_CTRL, &control);
663 if (rc) {
664 printf ("AML_V4L2_SET_DRMMODE fail\n");
665 }
666 }
667 return rc;
668}
669
Song Zhao6c7d1f82020-04-06 23:22:49 -0700670int v4l2_dec_init(enum vtype type, int secure, decode_finish_fn cb)
Song Zhao1b237602020-02-13 10:58:57 -0800671{
672 int ret = -1;
673 struct v4l2_capability cap;
674 struct v4l2_fmtdesc fdesc;
675 bool supported;
676
677 if (!cb)
678 return 1;
679 decode_finish_cb = cb;
680
Song Zhao6c7d1f82020-04-06 23:22:49 -0700681 if (secure) {
682 sInMemMode = V4L2_MEMORY_DMABUF;
683 ret = secmem_init();
684 if (ret) {
685 printf("secmem_init fail %d\n",ret);
686 return 1;
687 }
688 } else
689 sInMemMode = V4L2_MEMORY_MMAP;
690
Song Zhao1b237602020-02-13 10:58:57 -0800691 /* check decoder mode */
692 if ((type == VIDEO_TYPE_H264 ||
693 type == VIDEO_TYPE_MPEG2) &&
694 g_dw_mode != 16) {
695 printf("mpeg2/h264 only support DW 16 mode\n");
696 goto error;
697 }
698
699 /* config sys nodes */
700 if (config_sys_node("/sys/module/amvdec_ports/parameters/multiplanar", "1")) {
701 printf("set multiplanar fails\n");
702 goto error;
703 }
704 if (type == VIDEO_TYPE_VP9) {
705 if (config_sys_node("/sys/module/amvdec_ports/parameters/vp9_need_prefix", "1")) {
706 printf("set vp9_need_prefix fails\n");
707 goto error;
708 }
709 }
710 if (type == VIDEO_TYPE_MPEG2) {
711 //TODO: delete after ucode updated for mpeg2
712 if (config_sys_node("/sys/module/amvdec_ports/parameters/param_sets_from_ucode", "0")) {
713 printf("set param_sets_from_ucode 0 fails\n");
714 goto error;
715 }
716 }
717
718 pthread_mutex_init(&res_lock, NULL);
719 video_fd = open(video_dev_name, O_RDWR | O_NONBLOCK, 0);
720 if (video_fd < 0) {
721 printf("Unable to open video node: %s\n",
722 strerror(errno));
723 goto error;
724 }
725
726 if (type != VIDEO_TYPE_MPEG2) {
Song Zhao6c7d1f82020-04-06 23:22:49 -0700727 ret = v4l2_dec_set_drmmode(secure);
Song Zhao1b237602020-02-13 10:58:57 -0800728 if (ret) {
729 printf("aml_v4l2_dec_set_drmmode fail\n");
730 goto error;
731 }
732 }
733
734 if ((ret = ioctl(video_fd, VIDIOC_QUERYCAP, &cap))) {
735 printf("VIDIOC_QUERYCAP fails ret:%d\n", ret);
736 goto error;
737 }
738
739 if (!(cap.capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)) {
740 printf("V4L2_CAP_VIDEO_M2M_MPLANE fails\n");
741 goto error;
742 }
743 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
744 printf("V4L2_CAP_STREAMING fails\n");
745 goto error;
746 }
747
748 /* output fmt */
749 output_p.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
750 supported = false;
751 memset(&fdesc, 0, sizeof(fdesc));
752 fdesc.type = output_p.type;
753 for (;;) {
754 ret = ioctl(video_fd, VIDIOC_ENUM_FMT, &fdesc);
755 if (ret)
756 break;
757 if (v4l2_fourcc_to_vtype(fdesc.pixelformat) == type) {
758 supported = true;
759 output_p.pixelformat = fdesc.pixelformat;
760 break;
761 }
762 fdesc.index++;
763 }
764 if (!supported) {
765 printf("output format not supported:%d\n", type);
766 goto error;
767 }
768
769 if (config_decoder(video_fd, type)) {
770 printf("config_decoder error\n");
771 goto error;
772 }
773
774 memset(&output_p.sfmt, 0, sizeof(struct v4l2_format));
775 output_p.sfmt.type = output_p.type;
776 ret = ioctl(video_fd, VIDIOC_G_FMT, &output_p.sfmt);
777 if (ret) {
778 printf("VIDIOC_G_FMT fail\n");
779 goto error;
780 }
781
782 output_p.sfmt.fmt.pix_mp.pixelformat = output_p.pixelformat;
783 /* 4K frame should fit into 2M */
Song Zhao6c7d1f82020-04-06 23:22:49 -0700784 output_p.sfmt.fmt.pix_mp.plane_fmt[0].sizeimage = ES_BUF_SIZE;
Song Zhao1b237602020-02-13 10:58:57 -0800785 ret = ioctl(video_fd, VIDIOC_S_FMT, &output_p.sfmt);
786 if (ret) {
787 printf("VIDIOC_S_FMT 0x%x fail\n", output_p.pixelformat);
788 goto error;
789 }
790 output_p.plane_num = output_p.sfmt.fmt.pix_mp.num_planes;
791
792 /* capture fmt */
793 capture_p.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
794 supported = false;
795 memset(&fdesc, 0, sizeof(fdesc));
796 fdesc.type = capture_p.type;
797 for (;;) {
798 ret = ioctl(video_fd, VIDIOC_ENUM_FMT, &fdesc);
799 if (ret)
800 break;
801 if ((fdesc.pixelformat == V4L2_PIX_FMT_NV12M &&
802 g_dw_mode != VDEC_DW_AFBC_ONLY) ||
803 (fdesc.pixelformat == V4L2_PIX_FMT_NV12 &&
804 g_dw_mode == VDEC_DW_AFBC_ONLY)) {
805 supported = true;
806 capture_p.pixelformat = fdesc.pixelformat;
807 break;
808 }
809 fdesc.index++;
810 }
811 if (!supported) {
812 printf("capture format not supported\n");
813 goto error;
814 }
815
816 /* setup output port */
817 ret = setup_output_port(video_fd);
818 if (ret) {
819 printf("setup_output_port fail\n");
820 goto error;
821 }
822
823 /* start output port */
824 ret = ioctl(video_fd, VIDIOC_STREAMON, &output_p.type);
825 if (ret) {
826 printf("VIDIOC_STREAMON fail ret:%d\n",ret);
827 goto error;
828 }
829
830 printf("output stream on\n");
831 return 0;
832
833error:
834 close(video_fd);
835 video_fd = 0;
836 return ret;
837}
838
839static int handle_first_frame()
840{
841 int ret;
842 /* Wait for 1st video ES data and setup capture port */
843
844 ret = setup_capture_port(video_fd);
845 if (ret) {
846 printf(" setup_capture_port fail ret:%d\n",ret);
847 goto error;
848 }
849
850 pthread_mutex_init(&capture_p.lock, NULL);
851 pthread_cond_init(&capture_p.wait, NULL);
852
853 /* start capture port */
854 ret = ioctl(video_fd, VIDIOC_STREAMON, &capture_p.type);
855 if (ret) {
856 printf("VIDIOC_STREAMON fail ret:%d\n",ret);
857 goto error;
858 }
859 printf("capture stream on\n");
860
861 if (pthread_create(&dec_thread, NULL, dec_thread_func, NULL)) {
862 printf("dec thread fail\n");
863 return -1;
864 }
865 return 0;
866error:
867 printf("handle_first_frame fatal\n");
868 while (1) sleep(1);
869 exit(1);
870}
871
872int v4l2_dec_destroy()
873{
874 quit_thread = true;
875 pthread_cond_signal(&output_p.wait);
876 pthread_join(dec_thread, NULL);
877 destroy_output_port(video_fd);
878 destroy_capture_port(video_fd);
879 get_1st_data = false;
880 pthread_mutex_destroy(&res_lock);
881 close(video_fd);
Song Zhao6c7d1f82020-04-06 23:22:49 -0700882 secmem_destroy();
883 if (es_buf)
884 free(es_buf);
Song Zhao1b237602020-02-13 10:58:57 -0800885 return 0;
886}
887
888static int get_free_output_buf()
889{
890 int i;
891 pthread_mutex_lock(&output_p.lock);
892 do {
893 for (i = 0; i < output_p.buf_num; i++) {
894 if (!output_p.buf[i]->queued) {
895 break;
896 }
897 }
898
899 if (i == output_p.buf_num) {
900 pthread_cond_wait(&output_p.wait, &output_p.lock);
901 if (quit_thread)
902 break;
903 } else {
904 break;
905 }
906 } while (1);
907 pthread_mutex_unlock(&output_p.lock);
908
909 if (i == output_p.buf_num)
910 return -1;
911
912 return i;
913}
914
915#if 0
916static void dump(const char* path, const uint8_t *data, int size) {
917 FILE* fd = fopen(path, "ab");
918 if (!fd)
919 return;
920 fwrite(data, 1, size, fd);
921 fclose(fd);
922}
923#endif
924
925int v4l2_dec_write_es(const uint8_t *data, int size)
926{
927 struct frame_buffer *p;
928
929 if (cur_output_index == -1)
930 cur_output_index = get_free_output_buf();
931
932 if (cur_output_index < 0) {
933 printf("%s %d can not get output buf\n", __func__, __LINE__);
934 return 0;
935 }
936
937 p = output_p.buf[cur_output_index];
Song Zhao6c7d1f82020-04-06 23:22:49 -0700938 if ((sInMemMode == V4L2_MEMORY_MMAP &&
939 (p->used + size) > p->v4lplane[0].length) ||
940 (sInMemMode == V4L2_MEMORY_DMABUF &&
941 (p->used + size) > ES_BUF_SIZE)) {
942 printf("fatal frame too big %d\n",
943 size + p->used);
Song Zhao1b237602020-02-13 10:58:57 -0800944 return 0;
945 }
Song Zhao6c7d1f82020-04-06 23:22:49 -0700946
947 if (sInMemMode == V4L2_MEMORY_MMAP)
948 memcpy(p->vaddr[0] + p->used, data, size);
949 else
950 memcpy(es_buf + p->used, data, size);
951
Song Zhao1b237602020-02-13 10:58:57 -0800952 p->used += size;
953
954#ifdef DEBUG_FRAME
955 int i;
956 for (i = 0 ; i < size ; i++)
957 frame_checksum += data[i];
958#endif
959
960 //dump("/data/es.h265", data, size);
961 //
962 return size;
963}
964
965int v4l2_dec_frame_done()
966{
967 int ret;
968 struct frame_buffer *p;
969
970 if (quit_thread)
971 return 0;
972
973 if (cur_output_index < 0 || cur_output_index >= output_p.buf_num) {
974 printf("BUG %s %d idx:%d\n", __func__, __LINE__, cur_output_index);
975 return 0;
976 }
977 p = output_p.buf[cur_output_index];
Song Zhao6c7d1f82020-04-06 23:22:49 -0700978 if (sInMemMode == V4L2_MEMORY_DMABUF) {
979 /* copy to secmem */
980 p->smem = secmem_alloc(p->used);
981 if (!p->smem) {
982 printf("%s %d oom:%d\n", __func__, __LINE__, p->used);
983 return 0;
984 }
985 ret = secmem_fill(p->smem, es_buf, 0, p->used);
986 if (ret)
987 return 0;
988 p->v4lbuf.m.planes[0].m.fd = p->smem->fd;
989 p->v4lbuf.m.planes[0].length = p->used;
990 p->v4lbuf.m.planes[0].data_offset = 0;
991 }
Song Zhao1b237602020-02-13 10:58:57 -0800992 p->v4lbuf.m.planes[0].bytesused = p->used;
993 pthread_mutex_lock(&output_p.lock);
994 p->queued = true;
995 pthread_mutex_unlock(&output_p.lock);
996 ret = ioctl(video_fd, VIDIOC_QBUF, &p->v4lbuf);
997 if (ret) {
998 printf("write es VIDIOC_QBUF %dth buf fail ret:%d\n",
999 cur_output_index, ret);
1000 return 0;
1001 }
1002#ifdef DEBUG_FRAME
1003 printf("%s queue output %d frame_checksum:%x\n", __func__, cur_output_index, frame_checksum);
1004 frame_checksum = 0;
1005#endif
1006 d_o_push_num++;
1007 cur_output_index = -1;
1008 /* can setup capture port now */
1009 if (!get_1st_data) {
1010 printf("%s 1st frame done\n", __func__);
1011 get_1st_data = true;
1012 handle_first_frame();
1013 } else {
1014 }
1015 return ret;
1016}
1017
1018int capture_buffer_recycle(void* handle)
1019{
1020 int ret = 0;
1021 struct frame_buffer *frame = handle;
1022
1023 d_c_rec_num++;
1024 pthread_mutex_lock(&res_lock);
1025 if (frame->free_on_recycle) {
1026 printf("free index:%d\n", frame->v4lbuf.index);
1027 frame->drm_frame->destroy(frame->drm_frame);
1028 free(frame);
1029 goto exit;
1030 }
1031
1032 if (eos_received)
1033 goto exit;
1034
1035 ret = ioctl(video_fd, VIDIOC_QBUF, &frame->v4lbuf);
1036 if (ret) {
1037 printf("VIDIOC_QBUF %dth buf fail ret:%d\n", frame->v4lbuf.index, ret);
1038 goto exit;
1039 } else {
1040#ifdef DEBUG_FRAME
1041 printf("queue cap %d\n", frame->v4lbuf.index);
1042#endif
1043 frame->queued = true;
1044 }
1045exit:
1046 pthread_mutex_unlock(&res_lock);
1047 return ret;
1048}
1049
1050int v4l2_dec_eos()
1051{
1052 int ret;
1053 struct v4l2_decoder_cmd cmd = {
1054 .cmd = V4L2_DEC_CMD_STOP,
1055 .flags = 0,
1056 };
1057
1058 printf("%s EOS received\n", __func__);
1059 /* flush decoder */
1060 ret = ioctl(video_fd, VIDIOC_DECODER_CMD, &cmd);
1061 if (ret)
1062 printf("V4L2_DEC_CMD_STOP output fail ret:%d\n",ret);
1063
1064 return ret;
1065}
1066
1067void dump_v4l2_decode_state()
1068{
1069 printf("-----------------------\n");
1070 printf("output port: push(%d) pop(%d)\n", d_o_push_num, d_o_rec_num);
1071 printf("capture port: push(%d) pop(%d)\n", d_c_push_num, d_c_rec_num);
1072 printf("-----------------------\n");
1073}