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