/*_------------------------------------------------------------------------------*/ /* * Copyright (c) 2022, ArtInChip Technology Co., Ltd * * SPDX-License-Identifier: Apache-2.0 * */ #include #ifdef RT_USING_FINSH #include #include #include #include #include #include #include #include #include #include #include #include #include "artinchip_fb.h" #include "mpp_fb.h" #include "mpp_decoder.h" #include "mpp_mem.h" #include "packet_allocator.h" #include "usbh_uvc_stream.h" #define HEIGHT 480 #define WIDTH 640 struct usbh_uvc_player_t { /* AIC Disp parse*/ struct aicfb_video_layer *vlayer; struct mpp_fb *mpp_fb; struct mpp_decoder *mpp_dec; struct usbh_videoframe *cur_frame; usb_osal_thread_t record_tid; usb_osal_sem_t record_sem; int (*video_update_callback)(void *data); int buf_index; /* USB parse*/ uint8_t *frame_buffer1; uint8_t *frame_buffer2; /* stream data */ int video_fd; int frame_cnt; int max_frame_cnt; int width; int height; int image_size; uint8_t frame; uint8_t format_index; char format[32]; bool stream_on; bool stream_record; }g_usbh_uvc_player; #define UVC_DATA_PATH "/sdcard/uvc_data.raw" static struct usbh_videoframe frame_pool[2]; struct mpp_frame g_frame[2]; struct mpp_packet packet; int cur_frame_id = 0; int last_frame_id = 0; void usbh_video_fps_init(void); /* Global macro and variables */ #ifndef LOG_TAG #define LOG_TAG "de_test" #endif #define ERR(fmt, ...) aic_log(AIC_LOG_ERR, "E", fmt, ##__VA_ARGS__) #define DBG(fmt, ...) aic_log(AIC_LOG_INFO, "I", fmt, ##__VA_ARGS__) #define ALIGN_8B(x) (((x) + (7)) & ~(7)) #define ALIGN_16B(x) (((x) + (15)) & ~(15)) #define ALIGN_32B(x) (((x) + (31)) & ~(31)) #define ALIGN_64B(x) (((x) + (63)) & ~(63)) #define ALIGN_128B(x) (((x) + (127)) & ~(127)) #define ALIGN_1024B(x) (((x) + (1023)) & ~(1023)) #define AICFB_VID_BUF_NUM 2 struct video_data_format { enum mpp_pixel_format format; char f_str[16]; int plane_num; int y_shift; int u_shift; int v_shift; }; static struct video_data_format g_vformat[] = { {MPP_FMT_YUV420P, "yuv420p", 3, 0, 2, 2}, {MPP_FMT_YUV422P, "yuv422p", 3, 0, 1, 1}, {MPP_FMT_NV12, "nv12", 2, 0, 1, 0}, {MPP_FMT_NV21, "nv21", 2, 0, 1, 0}, {MPP_FMT_NV16, "nv16", 2, 0, 0, 0}, {MPP_FMT_NV61, "nv61", 2, 0, 0, 0}, {MPP_FMT_YUYV, "yuyv", 1, 1, 0, 0}, {MPP_FMT_YVYU, "yvyu", 1, 1, 0, 0}, {MPP_FMT_UYVY, "uyvy", 1, 1, 0, 0}, {MPP_FMT_VYUY, "vyuy", 1, 1, 0, 0}, {MPP_FMT_YUV400, "yuv400", 1, 0, 0, 0}, {MPP_FMT_YUV420_128x16_TILE, "yuv420_128x16", 2, 0, 1, 0}, {MPP_FMT_YUV420_64x32_TILE, "yuv420_64x32", 2, 0, 1, 0}, {MPP_FMT_YUV422_128x16_TILE, "yuv422_128x16", 2, 0, 0, 0}, {MPP_FMT_YUV422_64x32_TILE, "yuv422_64x32", 2, 0, 0, 0}, {MPP_FMT_YUV420P, "mjpeg", 3, 0, 2, 2}, {MPP_FMT_MAX, "", 0, 0, 0, 0} }; struct video_plane { void *buf; unsigned long phy_addr; int len; }; struct video_buf { struct video_plane y; struct video_plane u; struct video_plane v; }; struct aicfb_video_layer { int w; int h; int s; struct video_data_format *f; struct video_buf vbuf[AICFB_VID_BUF_NUM]; }; static struct aicfb_video_layer g_vlayer = {0}; static struct aicfb_layer_data g_layer = {0}; static struct mpp_fb *g_mpp_fb = NULL; static volatile uintptr_t g_uvc_fps = 0; static usb_osal_thread_t video_fps_tid; #define VIDEO_DEBUG static struct usbh_uvc_player_t *get_uvc_player(void) { return &g_usbh_uvc_player; } ATTR_FAST_RAM_SECTION void usbh_video_transfer_abort_callback(void) { g_uvc_fps = 0; } ATTR_FAST_RAM_SECTION void usbh_video_fps_record(void) { static uint32_t time_last; static uint16_t fps_cnt; fps_cnt++; if (fps_cnt >= 10) { uint32_t time = rt_tick_get(); g_uvc_fps = (1000 * 10) / (uint32_t)(time - time_last); time_last = time; fps_cnt = 0; } } static void usbh_vide_fps_thread(void *argument) { while (1) { usb_osal_msleep(5000); USB_LOG_INFO("fps:%u\n", (unsigned int)g_uvc_fps); USB_LOG_INFO("vc:%u\n", (unsigned int)video_complete_count); } } void usbh_video_fps_init(void) { video_fps_tid = usb_osal_thread_create("usbh_video", 1024 * 4, 10, usbh_vide_fps_thread, NULL); } void usbh_video_fps_deinit(void) { if (video_fps_tid) usb_osal_thread_delete(video_fps_tid); } /* Functions */ static inline bool format_invalid(enum mpp_pixel_format format) { if (format == MPP_FMT_MAX) return true; return false; } static inline bool is_packed_format(enum mpp_pixel_format format) { switch (format) { case MPP_FMT_YUYV: case MPP_FMT_YVYU: case MPP_FMT_UYVY: case MPP_FMT_VYUY: return true; default: break; } return false; } static inline bool is_tile_format(enum mpp_pixel_format format) { switch (format) { case MPP_FMT_YUV420_128x16_TILE: case MPP_FMT_YUV420_64x32_TILE: case MPP_FMT_YUV422_128x16_TILE: case MPP_FMT_YUV422_64x32_TILE: return true; default: break; } return false; } static inline bool is_plane_format(enum mpp_pixel_format format) { switch (format) { case MPP_FMT_YUV420P: case MPP_FMT_YUV422P: case MPP_FMT_YUV400: case MPP_FMT_NV12: case MPP_FMT_NV21: case MPP_FMT_NV16: case MPP_FMT_NV61: return true; default: break; } return false; } static inline bool is_2plane(enum mpp_pixel_format format) { switch (format) { case MPP_FMT_NV12: case MPP_FMT_NV21: case MPP_FMT_NV16: case MPP_FMT_NV61: return true; default: break; } return false; } static inline bool is_tile_16_align(enum mpp_pixel_format format) { switch (format) { case MPP_FMT_YUV420_128x16_TILE: case MPP_FMT_YUV422_128x16_TILE: return true; default: break; } return false; } static inline bool is_tile_32_align(enum mpp_pixel_format format) { switch (format) { case MPP_FMT_YUV420_64x32_TILE: case MPP_FMT_YUV422_64x32_TILE: return true; default: break; } return false; } static int aicfb_open(void) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); if (g_mpp_fb) return 0; g_mpp_fb = mpp_fb_open(); if (!g_mpp_fb) { ERR("open mpp fb failed\n"); return -1; } uvc_player->mpp_fb = g_mpp_fb; mpp_fb_ioctl(g_mpp_fb, AICFB_POWERON, 0); return 0; } static int vidbuf_request_one(struct video_plane *plane, int len) { plane->len = len; plane->buf = usb_osal_malloc_align(MEM_CMA, len + 1023, 1024); if (!plane->buf) { ERR("memory alloc failed, need %d bytes", len); return -1; } plane->phy_addr = ALIGN_1024B((unsigned long)plane->buf); USB_LOG_DBG("Alloc vidbuf 0x%lx phy_addr 0x%lx len %d\n", (long)plane->buf, (long)plane->phy_addr, len); return 0; } static int vidbuf_request(struct aicfb_video_layer *vlayer) { int i, j; int y_frame = vlayer->w * vlayer->h; /* Prepare two group buffer for video player, and each group has three planes: y, u, v. */ for (i = 0; i < AICFB_VID_BUF_NUM; i++) { struct video_plane *p = (struct video_plane *)&vlayer->vbuf[i]; int *shift = &vlayer->f->y_shift; if (is_packed_format(vlayer->f->format)) { vidbuf_request_one(p, y_frame << shift[0]); frame_pool[i].frame_buf = (uint8_t *)p->phy_addr; frame_pool[i].frame_bufsize = p->len; } if (is_plane_format(vlayer->f->format)) { vidbuf_request_one(p, y_frame * 3 / 2); frame_pool[i].frame_buf = (uint8_t *)p->phy_addr; frame_pool[i].frame_bufsize = p->len; for (j = 0, p++; j < vlayer->f->plane_num - 1; j++, p++) { p->phy_addr = ((uintptr_t)frame_pool[i].frame_buf + (y_frame >> shift[j])); } } USB_LOG_DBG("frame_pool[%d]:%#lx size :%d\n", i, (long)frame_pool[i].frame_buf, frame_pool[i].frame_bufsize); } return 0; } void vidbuf_release(struct aicfb_video_layer *vlayer) { int i; struct video_plane *p = NULL; for (i = 0; i < AICFB_VID_BUF_NUM; i++) { p = (struct video_plane *)&vlayer->vbuf[i]; if (p->buf == NULL) continue; USB_LOG_DBG("free p 0x%lx\n", (long)p); usb_osal_free_align(MEM_CMA, p->buf); USB_LOG_DBG("free buf 0x%lx\n", (long)p->buf); } } static int set_ui_layer_alpha(int val) { int ret = 0; struct aicfb_alpha_config alpha = {0}; alpha.layer_id = AICFB_LAYER_TYPE_UI; alpha.mode = AICFB_GLOBAL_ALPHA_MODE; alpha.enable = 1; alpha.value = val; ret = mpp_fb_ioctl(g_mpp_fb, AICFB_UPDATE_ALPHA_CONFIG, &alpha); if (ret < 0) ERR("ioctl update alpha config failed!\n"); return ret; } static int video_layer_set_yuv(struct aicfb_video_layer *vlayer, int index) { struct video_buf *vbuf = &vlayer->vbuf[index]; memset(&g_layer, 0, sizeof(g_layer)); g_layer.layer_id = AICFB_LAYER_TYPE_VIDEO; g_layer.enable = 1; g_layer.pos.x = 0; g_layer.pos.y = 0; g_layer.scale_size.width = vlayer->w; g_layer.scale_size.height = vlayer->h; g_layer.buf.size.width = vlayer->w; g_layer.buf.size.height = vlayer->h; g_layer.buf.format = vlayer->f->format; g_layer.buf.buf_type = MPP_PHY_ADDR; g_layer.buf.phy_addr[0] = vbuf->y.phy_addr; g_layer.buf.phy_addr[1] = vbuf->u.phy_addr; g_layer.buf.phy_addr[2] = vbuf->v.phy_addr; if (is_packed_format(vlayer->f->format)) g_layer.buf.stride[0] = vlayer->w << 1; if (is_tile_format(vlayer->f->format)) { g_layer.buf.stride[0] = vlayer->s; g_layer.buf.stride[1] = vlayer->s; } if (is_plane_format(vlayer->f->format)) { g_layer.buf.stride[0] = vlayer->w; g_layer.buf.stride[1] = is_2plane(vlayer->f->format) ? vlayer->w : vlayer->w >> 1; g_layer.buf.stride[2] = vlayer->w >> 1; } if (mpp_fb_ioctl(g_mpp_fb, AICFB_UPDATE_LAYER_CONFIG, &g_layer) < 0) { ERR("ioctl update layer config failed!\n"); return -1; } return 0; } void video_layer_disable(void) { struct aicfb_layer_data layer = {0}; layer.layer_id = AICFB_LAYER_TYPE_VIDEO; layer.enable = 0; if (mpp_fb_ioctl(g_mpp_fb, AICFB_UPDATE_LAYER_CONFIG, &layer) < 0) ERR("ioctl update layer config failed!\n"); } static void vidbuf_cpu_begin(struct video_buf *vbuf) { } static void vidbuf_cpu_end(struct video_buf *vbuf) { int i; struct video_plane *p = (struct video_plane *)vbuf; for (i = 0; i < g_vlayer.f->plane_num; i++, p++) aicos_dcache_clean_invalid_range((unsigned long *)p->phy_addr, p->len); } static int format_parse(char *str) { int i; for (i = 0; g_vformat[i].format != MPP_FMT_MAX; i++) { if (strncmp(g_vformat[i].f_str, str, strlen(str)) == 0) return i; } ERR("Invalid format: %s\n", str); return -1; } static int vidbuf_write(struct usbh_videoframe *frame) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); int fd = uvc_player->video_fd; if (uvc_player->frame_cnt > uvc_player->max_frame_cnt) return 0; write(fd, (void *)frame->frame_buf, frame->frame_bufsize); fsync(fd); uvc_player->frame_cnt++; if (uvc_player->frame_cnt == uvc_player->max_frame_cnt) close(fd); return 0; } static void uvc_record_thread(void *arg) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); while (1) { if (usb_osal_sem_take(uvc_player->record_sem, AICOS_WAIT_FOREVER)) break; vidbuf_write(uvc_player->cur_frame); } } static void uvc_record_start(int max_frame_cnt) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); if (uvc_player->max_frame_cnt != 0 && uvc_player->frame_cnt < uvc_player->max_frame_cnt) return; uvc_player->stream_record = true; uvc_player->frame_cnt = 0; uvc_player->max_frame_cnt = max_frame_cnt; USB_LOG_INFO("UVC start recoring.(max frame cnt: %d)\n", uvc_player->max_frame_cnt); uvc_player->video_fd = open(UVC_DATA_PATH, O_RDWR); if (uvc_player->video_fd < 0) { creat(UVC_DATA_PATH, O_RDWR); uvc_player->video_fd = open(UVC_DATA_PATH, O_RDWR); } if (uvc_player->stream_record == true && uvc_player->record_sem == NULL && uvc_player->record_tid == NULL) { uvc_player->record_sem = usb_osal_sem_create(0); uvc_player->record_tid = usb_osal_thread_create("uvc_record", 1024 * 6, 18, uvc_record_thread, NULL); } } static void uvc_player_info(struct usbh_uvc_player_t *uvc_player) { int info_width = 40; for (int i = 0; i < info_width / 2; i++) { printf("-"); } printf(" UVC player parsemeter "); for (int i = 0; i < info_width / 2; i++) { printf("-"); } printf("\n"); printf("| UVC player status -> %s \n", uvc_player->stream_on ? "on" : "off"); printf("| frame buffer1 : %#lx\n", (long)uvc_player->frame_buffer1); printf("| frame buffer2 : %#lx\n", (long)uvc_player->frame_buffer2); printf("| Format\t |\tWidth\t|\tHeight\t|\tFrame\t\n"); printf("\t%s\t", uvc_player->format); printf("\t %d\t", uvc_player->width); printf("\t %d\t", uvc_player->height); printf("\t %u\t", (unsigned int)g_uvc_fps); printf("\n"); for (int i = 0; i < (info_width + 23); i++) { printf("-"); } printf("\n"); } static void usb_video_soft_reset(void) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); memset(uvc_player, 0, sizeof(struct usbh_uvc_player_t)); memset(&g_vlayer, 0, sizeof(struct aicfb_video_layer)); uvc_player->vlayer = &g_vlayer; uvc_player->mpp_fb = g_mpp_fb; //set default parse uvc_player->height = HEIGHT; uvc_player->width = WIDTH; uvc_player->frame = 15; strcpy(uvc_player->format, "yuyv"); uvc_player->format_index = USBH_VIDEO_FORMAT_UNCOMPRESSED_YUY2; } static int usb_video_src_release(void) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); switch (UVC_GET_FORMAT(uvc_player->format_index)) { case USBH_VIDEO_FORMAT_UNCOMPRESSED: video_layer_disable(); if (uvc_player->vlayer) vidbuf_release(uvc_player->vlayer); break; case USBH_VIDEO_FORMAT_MJPEG: for (int i = 0; i < 2; i++) { usb_osal_free_align(MEM_CMA, frame_pool[i].frame_buf); } break; default: break; } if (uvc_player->record_tid) usb_osal_thread_delete(uvc_player->record_tid); if (uvc_player->record_sem) usb_osal_sem_delete(uvc_player->record_sem); usb_video_soft_reset(); usbh_video_fps_deinit(); return 0; } static int parse_options(struct usbh_uvc_player_t *uvc_player, int cnt, char**options) { int argc = cnt; char **argv = options; int opt; if (!uvc_player || argc == 0 || !argv) { USB_LOG_ERR("para error !!!"); return -1; } optind = 0; while (1) { opt = getopt(argc, argv, "w:h:f:r:isl"); if (opt == -1) { break; } switch (opt) { case 'h': uvc_player->height = strtoul(optarg, NULL, 10); break; case 'w': uvc_player->width = strtoul(optarg, NULL, 10); break; case 'f': if (strcmp(optarg, "nv12") == 0) { uvc_player->format_index = USBH_VIDEO_FORMAT_UNCOMPRESSED_NV12; strcpy(uvc_player->format, "nv12"); } if (strcmp(optarg, "yuy2") == 0 || strcmp(optarg, "yuyv") == 0 ) { uvc_player->format_index = USBH_VIDEO_FORMAT_UNCOMPRESSED_YUY2; strcpy(uvc_player->format, "yuyv"); } if (strcmp(optarg, "mjpeg") == 0) { uvc_player->format_index = USBH_VIDEO_FORMAT_MJPEG; strcpy(uvc_player->format, "mjpeg"); } break; case 's': if (uvc_player->stream_on == false) return -1; uvc_player->stream_on = false; usbh_video_stream_stop(); rt_thread_mdelay(50); usbh_video_stream_deinit(); rt_thread_mdelay(50); usb_video_src_release(); return -1; case 'r': uvc_record_start(strtoul(optarg, NULL, 10)); break; case 'l': usbh_video_format_list(); return -1; case 'i': uvc_player_info(uvc_player); return -1; default: return -1; } } return 0; } static int usbh_disp_parse_set(struct usbh_uvc_player_t *uvc_player) { int index; g_vlayer.w = uvc_player->width; g_vlayer.h = uvc_player->height; index = format_parse(uvc_player->format); if (index < 0) return 0; g_vlayer.f = &g_vformat[index]; return 0; } static void uvc_yuv_init(void) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); vidbuf_request(uvc_player->vlayer); video_layer_set_yuv(uvc_player->vlayer, uvc_player->buf_index); } static int uvc_yuv_update_callback(void *data) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); struct video_buf *vbuf; vbuf = &g_vlayer.vbuf[uvc_player->buf_index]; vidbuf_cpu_begin(vbuf); vidbuf_cpu_end(vbuf); video_layer_set_yuv(&g_vlayer, uvc_player->buf_index); uvc_player->buf_index = !uvc_player->buf_index; return 0; } static int pkt_allocator_init(struct packet_allocator *p) { return 0; } static int pkt_allocator_deinit(struct packet_allocator *p) { return 0; } static int pkt_alloc(struct packet_allocator *p,struct mpp_packet *packet) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); packet->data = uvc_player->cur_frame->frame_buf; packet->size = uvc_player->cur_frame->frame_bufsize; packet->flag = PACKET_FLAG_EOS; return 0; } static int pkt_free(struct packet_allocator *p,struct mpp_packet *packet) { return 0; } static struct pkt_alloc_ops pkt_ops = { .allocator_init = pkt_allocator_init, // allocator_init .allocator_deinit = pkt_allocator_deinit, // allocator_deinit .alloc = pkt_alloc, // alloc .free = pkt_free, // free }; static struct packet_allocator pkt_allocator = { .ops = &pkt_ops, }; static int aic_uvc_player_update_callback(void *data) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); uvc_player->cur_frame = (struct usbh_videoframe *)data; uvc_player->video_update_callback(data); if (uvc_player->stream_record == true || uvc_player->record_sem) usb_osal_sem_give(uvc_player->record_sem); return 0; } static int aic_uvc_player_deinit_callback(void *data) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); if (uvc_player->stream_on == false) return -1; uvc_player->stream_on = false; usbh_video_stream_stop(); rt_thread_mdelay(50); usbh_video_stream_deinit(); rt_thread_mdelay(50); usb_video_src_release(); return 0; } static int usb_disp_ve_update_buf_size(struct mpp_frame *frame) { int w = frame->buf.size.width; int h = frame->buf.size.height; if ((w > h && frame->buf.crop.width < frame->buf.crop.height) || (w < h && frame->buf.crop.width > frame->buf.crop.height)) { frame->buf.size.width = h; frame->buf.size.height = w; } return 0; } static int usb_disp_decoder_init(void) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); struct decode_config config; uint32_t usb_ve_rotate = 0; if (uvc_player->format_index & USBH_VIDEO_FORMAT_MJPEG) uvc_player->mpp_dec = mpp_decoder_create(MPP_CODEC_VIDEO_DECODER_MJPEG); else if (uvc_player->format_index & USBH_VIDEO_FORMAT_H264) uvc_player->mpp_dec = mpp_decoder_create(MPP_CODEC_VIDEO_DECODER_H264); else uvc_player->mpp_dec = NULL; if (!uvc_player->mpp_dec) { USB_LOG_ERR("mpp_dec_create failed.\n"); return -1; } mpp_decoder_control(uvc_player->mpp_dec, MPP_DEC_INIT_CMD_SET_EXT_PACKET_ALLOCATOR, &pkt_allocator); config.bitstream_buffer_size = ALIGN_UP(uvc_player->image_size, 1024); if (uvc_player->format_index & USBH_VIDEO_FORMAT_MJPEG) config.extra_frame_num = 1; else config.extra_frame_num = 0; config.packet_count = 1; config.pix_fmt = MPP_FMT_YUV420P; mpp_decoder_init(uvc_player->mpp_dec, &config); if (uvc_player->format_index & USBH_VIDEO_FORMAT_MJPEG) { mpp_decoder_control(uvc_player->mpp_dec, MPP_DEC_INIT_CMD_SET_ROT_FLIP_FLAG, &usb_ve_rotate); } return 0; } static int usb_disp_render_frame(int cur_frame_id, int last_frame_id) { int ret = 0; struct usbh_uvc_player_t *uvc_player = get_uvc_player(); struct mpp_frame *pframe = &g_frame[cur_frame_id]; struct mpp_frame *last_pframe = &g_frame[last_frame_id]; ret = mpp_decoder_get_frame(uvc_player->mpp_dec, pframe); if (ret) { USB_LOG_ERR("mpp_decoder_get_frame error = %d.\n", ret); return ret; } else { USB_LOG_DBG("mpp_decoder_get_frame succeed.\n"); } if (uvc_player->format_index != USBH_VIDEO_FORMAT_MJPEG) { mpp_decoder_put_frame(uvc_player->mpp_dec, pframe); memset(pframe, 0, sizeof(struct mpp_frame)); } else { //Update ve output buffer size usb_disp_ve_update_buf_size(pframe); memcpy(&g_layer.buf, &pframe->buf, sizeof(struct mpp_buf)); } mpp_fb_ioctl(uvc_player->mpp_fb, AICFB_UPDATE_LAYER_CONFIG, &g_layer); if (last_pframe->buf.phy_addr[0]) { mpp_decoder_put_frame(uvc_player->mpp_dec, last_pframe); memset(last_pframe, 0, sizeof(struct mpp_frame)); } return 0; } static void uvc_decode_init(void) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); uint32_t max_frame_size = ALIGN_UP((uvc_player->width * uvc_player->height * 3) / 2, 16) + 16; memset(g_frame, 0, sizeof(g_frame)); for (int i = 0; i < 2; i++) { if ((uvc_player->format_index == USBH_VIDEO_FORMAT_H264)) frame_pool[i].frame_buf = usb_osal_malloc_align(MEM_CMA, max_frame_size, 1024); else frame_pool[i].frame_buf = usb_osal_malloc_align(MEM_CMA, max_frame_size, CACHE_LINE_SIZE); frame_pool[i].frame_bufsize = max_frame_size; } if (video_layer_set_yuv(uvc_player->vlayer, 0)) return; uvc_player->image_size = max_frame_size; if (usb_disp_decoder_init()) return; } static int uvc_decode_update_callback(void *data) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); int ret = 0; int buff_len= ALIGN_UP((uvc_player->width * uvc_player->height * 3) / 2, 16) + 16; memset(&packet, 0, sizeof(struct mpp_packet)); ret = mpp_decoder_get_packet(uvc_player->mpp_dec, &packet, buff_len); if (ret) { USB_LOG_ERR("mpp_decoder_get_packet error = %d.\n", ret); return -1; } else { USB_LOG_DBG("mpp_decoder_get_packet succeed.\n"); } ret = mpp_decoder_put_packet(uvc_player->mpp_dec, &packet); if (ret) { USB_LOG_ERR("mpp_decoder_put_packet error = %d.\n", ret); return -1; } else { USB_LOG_DBG("mpp_decoder_put_packet succeed.\n"); } ret = mpp_decoder_decode(uvc_player->mpp_dec); if (ret == DEC_NO_EMPTY_FRAME) { USB_LOG_DBG("mpp_decoder_decode error, no empty frame.\n"); } else if (ret) { USB_LOG_ERR("mpp_decoder_decode error = %d.\n", ret); if (uvc_player->stream_record == true || uvc_player->record_sem) usb_osal_sem_give(uvc_player->record_sem); return -1; } else { USB_LOG_DBG("mpp_decoder_decode succeed.\n"); } if (cur_frame_id == 0) last_frame_id = 1; else last_frame_id = 0; ret = usb_disp_render_frame(cur_frame_id, last_frame_id); if (ret) { return -1; } if (cur_frame_id == 0) cur_frame_id = 1; else cur_frame_id = 0; return 0; } static void test_usbh_video(int argc, char **argv) { struct usbh_uvc_player_t *uvc_player = get_uvc_player(); int ret = -1; if (uvc_player->stream_on == false) { usb_video_soft_reset(); } ret = parse_options(uvc_player, argc, argv); if (ret < 0) return; if (uvc_player->stream_on == true) { USB_LOG_RAW("UVC player has been started.\n"); return; } ret = usbh_disp_parse_set(uvc_player); if (ret < 0) USB_LOG_ERR("Payer don't support this format.\n"); if (aicfb_open() < 0) USB_LOG_ERR("aic fb open fail.\n"); set_ui_layer_alpha(0); switch (UVC_GET_FORMAT(uvc_player->format_index)) { case USBH_VIDEO_FORMAT_UNCOMPRESSED: uvc_yuv_init(); uvc_player->video_update_callback = uvc_yuv_update_callback; break; case USBH_VIDEO_FORMAT_MJPEG: uvc_decode_init(); uvc_player->video_update_callback = uvc_decode_update_callback; break; default: USB_LOG_ERR("uvc player playback format abnormality.\n"); return; } if (uvc_player->video_update_callback == NULL) { USB_LOG_ERR("Failed to start uvc player.\n"); return; } uvc_player->frame_buffer1 = frame_pool[0].frame_buf; uvc_player->frame_buffer2 = frame_pool[1].frame_buf; usbh_video_stream_init(5, frame_pool, AICFB_VID_BUF_NUM); usbh_video_player_register(aic_uvc_player_update_callback); usbh_video_player_deinit_register(aic_uvc_player_deinit_callback); usbh_video_fps_init(); usbh_video_stream_start(uvc_player->width, uvc_player->height, uvc_player->format_index); uvc_player->stream_on = true; } MSH_CMD_EXPORT_ALIAS(test_usbh_video, test_usbh_video, usb video layer test); #endif /* RT_USING_FINSH */