/* * Copyright (c) 2023~2024 Quaming Intelligent Technology Co., Ltd. * * All Rights Reserved. * Confidential and Proprietary - Quaming Intelligent Technology Co., Ltd. */ #include #include #include #include #include #include #include "common/qua_mm_common.h" #include "common/qua_sys_platform.h" #include "video/qua_mm_video.h" #include "system/qua_mm_system.h" #define INPUT_FRAME_NUM 300 #define ALIGNTO(x, align) (((x) + (align) - 1) & ~((align) - 1)) static void print_usage(char* prog) { printf("Usage: %s -p primary -c --chip-name -o --os-name -i stream_file -w img-width -h img-height -f coding_format -n channels -v vb_count --d yuv_file\n",prog); printf("\t -p --primary-user : whether this sample is primary user(1: primary user; 0: non-primary user)\n"); printf("\t -c --chip-name : chip name, such as mc6870 or mc331x\n"); printf("\t -o --os-name : os name, such as android or rtt\n"); printf("\t -i --stream_file : the full path of the stream file\n"); printf("\t -w --img-width : the width of image\n"); printf("\t -h --img-height : the height of image\n"); printf("\t -f --coding_format : coding type. such as h264\n"); printf("\t -n --channels : channel of decoder.\n"); printf("\t -v --vb_count : vb cnt. \n"); printf("\t -d --output : the full path of the output file\n"); } static qua_coding_type_t get_coding_type(char *stype) { qua_coding_type_t coding_type = QUA_VIDEO_CodingUnused; if(strcasecmp(stype, "h264") == 0) { coding_type = QUA_VIDEO_CodingAVC; } else if(strcasecmp(stype, "h265") == 0) { coding_type = QUA_VIDEO_CodingHEVC; } else if(strcasecmp(stype, "jpeg") == 0) { coding_type = QUA_VIDEO_CodingJpeg; } else if(strcasecmp(stype, "mjpeg") == 0) { coding_type = QUA_VIDEO_CodingMJpeg; } return coding_type; } QUA_S32 findStreamFrame(QUA_U8* pu8Buf, QUA_S32 bufLen, qua_coding_type_t codingType, QUA_S32* s32Start) { QUA_BOOL bFindStart = QUA_FALSE; QUA_BOOL bFindEnd = QUA_FALSE; QUA_S32 i, s32FrameLen = -1; QUA_U32 u32Len = 0; switch(codingType) { case QUA_VIDEO_CodingAVC: { *s32Start = 0; for (i=0; i 0) s32FrameLen = i; if (bFindStart == QUA_FALSE) { printf("can not find H264 start code\n"); s32FrameLen = -1; } if (bFindEnd == QUA_FALSE) { s32FrameLen = i + 9; } } break; case QUA_VIDEO_CodingHEVC: { *s32Start = 0; QUA_BOOL bNewPic = QUA_FALSE; for (i = 0; i < bufLen - 7; i++) { QUA_U32 tmp = (pu8Buf[i+4]&0x7E)>>1; bNewPic = (QUA_BOOL)( pu8Buf[i+0] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 0 && pu8Buf[i+3] == 1 && (tmp <= 21) && ((pu8Buf[i+6]&0x80) == 0x80) ); if (bNewPic) { bFindStart = QUA_TRUE; i += 7; break; } } for (; i>1; bNewPic = (QUA_BOOL)(pu8Buf[i+0] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 0 && pu8Buf[i+3] == 1 &&( tmp == 32 || tmp == 33 || tmp == 34 || tmp == 39 || tmp == 40 || ((tmp <= 21) && (pu8Buf[i+6]&0x80) == 0x80) ) ); if (bNewPic) { bFindEnd = QUA_TRUE; break; } } if(i>0)s32FrameLen = i; if (bFindStart == QUA_FALSE) { printf("can not find H265 start code!\n"); s32FrameLen = -1; } if (bFindEnd == QUA_FALSE) { s32FrameLen = i + 7; } } break; case QUA_VIDEO_CodingJpeg: case QUA_VIDEO_CodingMJpeg: { for (i = 0; i< bufLen - 1; i++) { if (pu8Buf[i] == 0xFF && pu8Buf[i+1] == 0xD8) { *s32Start = i; bFindStart = QUA_TRUE; i = i + 2; break; } } for (; i< bufLen - 3; i++) { if ((pu8Buf[i] == 0xFF) && (pu8Buf[i+1]& 0xF0) == 0xE0) { u32Len = (pu8Buf[i+2]<<8) + pu8Buf[i+3]; i += 1 + u32Len; } else { break; } } for (; isys_init(&vb_cfg); } *sys_ops = ops; } int main(int argc, char* argv[]) { QUA_CHAR stream_path[256]; FILE *fp_strm = NULL; QUA_CHAR frame_path[256]; FILE *fp_frm = NULL; QUA_CHAR chip_name[16]; QUA_CHAR os_name[16]; QUA_CHAR platform[32]; QUA_CHAR tmp_buf[8]; QUA_S32 vb_cnt = 0; QUA_S32 chn_id; QUA_U32 width; QUA_U32 height; QUA_U8 *pu8_buf = NULL; QUA_U32 buf_len = 0; QUA_U32 used_bytes = 0; QUA_U32 read_len = 0; QUA_U32 frame_len = 0; QUA_S32 start = 0; QUA_U32 frame_cnt = 0; QUA_U32 max_input_cnt = 0; qua_coding_type_t coding_type; qua_vdec_stream_t packet; qua_video_frame_info_t out_frame; QUA_S32 err = 0; QUA_BOOL primary; QUA_S32 vdec_fd; fd_set vdec_read_fds; struct timeval timeout_val; QUA_S32 ret; ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_CHIP_NAME, chip_name, sizeof(chip_name)); if (ret == QUA_FAILURE) { printf("get chip name error!\n"); print_usage(argv[0]); return ret; } ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_OS_NAME, os_name, sizeof(os_name)); if (ret == QUA_FAILURE) { printf("get os name error!\n"); print_usage(argv[0]); return ret; } ret = qua_make_platform(chip_name, os_name, platform, sizeof(platform)); if (ret == QUA_FAILURE) { printf("make platform name error!\n"); return ret; } ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_IMAGE_WIDTH, tmp_buf, sizeof(tmp_buf)); if (ret == QUA_FAILURE) { printf("get image width error!\n"); print_usage(argv[0]); return ret; } width = atoi(tmp_buf); ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_IMAGE_HEIGHT, tmp_buf, sizeof(tmp_buf)); if (ret == QUA_FAILURE) { printf("get image height error!\n"); print_usage(argv[0]); return ret; } height = atoi(tmp_buf); ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_INPUT_FILE, stream_path, sizeof(stream_path)); if (ret == QUA_FAILURE) { printf("get input file error!\n"); print_usage(argv[0]); return ret; } ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_OUTPUT_FILE, frame_path, sizeof(frame_path)); if (ret == QUA_FAILURE) { printf("get ouput file error!\n"); } ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_CHANNEL_ID, tmp_buf, sizeof(tmp_buf)); if (ret == QUA_FAILURE) { printf("get channel id error!\n"); print_usage(argv[0]); return ret; } chn_id = atoi(tmp_buf); ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_VB_COUNT, tmp_buf, sizeof(tmp_buf)); if (ret == QUA_FAILURE) { printf("get channel id error!\n"); print_usage(argv[0]); return ret; } vb_cnt = atoi(tmp_buf); ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_CODING_FORMAT, tmp_buf, sizeof(tmp_buf)); if (ret == QUA_FAILURE) { printf("get coding format error!\n"); print_usage(argv[0]); return ret; } coding_type = get_coding_type(tmp_buf); ret = qua_get_cmdline_arg(argc, argv, QUA_ARG_PRIMARY_USER, tmp_buf, sizeof(tmp_buf)); if (ret == QUA_FAILURE) { printf("get primary value error!\n"); print_usage(argv[0]); return ret; } primary = atoi(tmp_buf); printf("==============start qua mm vdec test============\n"); printf("stream file: %s\n", stream_path); printf("frame file: %s\n", frame_path); printf("coding_type: %d\n", coding_type); printf("number of channels: %d\n", chn_id); printf("vb_cnt: %d\n", vb_cnt); printf("vdec dimention: %d x %d\n", width, height); fp_strm = fopen(stream_path, "rb"); if (fp_strm == NULL) { printf("can't open stream %s (%s)\n", stream_path, strerror(errno)); return -1; } fp_frm = fopen(frame_path, "wb"); if (fp_frm == NULL) { printf("can't open frm %s (%s)\n", frame_path, strerror(errno)); } printf("platform: %s\n", platform); qua_mm_system_ops_t *sys_ops = NULL; qua_mm_get_sys_ops(platform, primary, &sys_ops); const qua_mm_module_t *video_module = NULL; ret = qua_mm_load_module(QUA_MM_MODULE_VIDEO, &video_module); if (ret != QUA_SUCCESS || video_module == NULL) return -1; printf("Module %s, API version %d\n", video_module->id, video_module->api_version); qua_mm_device_t *mm_device = NULL; ret = video_module->open_device(video_module, QUA_MM_VIDEO_DEV_DEC, 0, &mm_device); if (ret != QUA_SUCCESS || mm_device == NULL) return -1; qua_mm_vdec_device_t *vdec_device = (qua_mm_vdec_device_t *)mm_device; printf("Device %s\n", vdec_device->parent.id); QUA_U32 bufSize = width * height; if (width * height > 3840 * 2160) bufSize = bufSize * 2; qua_vdec_chn_attr_t chn_attr; chn_attr.coding_type = coding_type; chn_attr.in_stream_buf_size = bufSize; chn_attr.priority = 5; chn_attr.pic_width = width; chn_attr.pic_height = height; chn_attr.vdec_video_attr.mode = QUA_VIDEO_MODE_FRAME; if (coding_type == QUA_VIDEO_CodingAVC) { chn_attr.vdec_video_attr.temporal_mvp_enable = 0; } else if (coding_type == QUA_VIDEO_CodingHEVC) { chn_attr.vdec_video_attr.temporal_mvp_enable = 1; } else if (coding_type == QUA_VIDEO_CodingJpeg || coding_type == QUA_VIDEO_CodingMJpeg) { chn_attr.vdec_jpeg_attr.mode = QUA_VIDEO_MODE_FRAME; chn_attr.vdec_jpeg_attr.jpeg_fmt = QUA_JPG_COLOR_FMT_YCBCR420; } qua_mm_channel_t *mm_channel; qua_mm_vdec_chn_attr_t vdec_chn_attr; vdec_chn_attr.chn_attr = chn_attr; vdec_chn_attr.vb_cnt = vb_cnt; vdec_device->parent.create_channel(mm_device, &chn_id, (QUA_VOID_PTR)&vdec_chn_attr, &mm_channel); qua_vdec_chn_param_t chn_param; qua_mm_vdec_channel_t *vdec_chn = (qua_mm_vdec_channel_t*)mm_channel; vdec_chn->get_chn_param(chn_id, &chn_param); chn_param.dec_order_output = 0; // display order chn_param.chan_err_thr = 1; vdec_chn->set_chn_param(chn_id, &chn_param); vdec_chn->start_chn(chn_id); buf_len = width * height; pu8_buf = (QUA_U8 *)malloc(buf_len); max_input_cnt = (coding_type == QUA_VIDEO_CodingJpeg) ? 1 : INPUT_FRAME_NUM; while(frame_cnt++ < max_input_cnt) { fseek(fp_strm, used_bytes, SEEK_SET); read_len = fread(pu8_buf, 1, buf_len, fp_strm); if (read_len == 0) break; frame_len = findStreamFrame(pu8_buf, read_len, coding_type, &start); memset(&packet, 0, sizeof(qua_vdec_stream_t)); packet.pts = 0; packet.in_data = (QUA_U64)(pu8_buf + start); packet.in_size = frame_len; packet.end_of_frame = QUA_TRUE; packet.end_of_stream = QUA_FALSE; printf("sendStream bufLen:%d, s32ReadLen:%d, s32FrameLen:%d, s32Start:%d\n", buf_len, read_len, frame_len, start); used_bytes += start + frame_len; vdec_chn->send_stream(chn_id, &packet, -1); vdec_fd = vdec_chn->get_chn_fd(chn_id); FD_ZERO(&vdec_read_fds); FD_SET(vdec_fd, &vdec_read_fds); timeout_val.tv_sec = 0; timeout_val.tv_usec = 20000; ret = select(vdec_fd + 1, &vdec_read_fds, NULL, NULL, &timeout_val); if (ret <= 0) { usleep(100000); continue; } err = vdec_chn->get_frame(chn_id, &out_frame, 0); if (err != QUA_SUCCESS) { printf("getFrame error %d", __LINE__); break; } QUA_S32 hor_stride; QUA_S32 ver_stride; QUA_S32 align = (coding_type == QUA_VIDEO_CodingJpeg) ? 16 : 64; hor_stride = ALIGNTO(out_frame.video_frame.width, align); ver_stride = ALIGNTO(out_frame.video_frame.height, align); QUA_VOID *vaddr = sys_ops->sys_mmap(out_frame.video_frame.phy_addr[0], hor_stride * ver_stride * 3/2); printf("mmap vaddr %p compress 0x%x wxh %dx%d stride 0 %d u32PhyAddr 0 %lld\n", vaddr, out_frame.video_frame.compress_mode, out_frame.video_frame.width, out_frame.video_frame.height, out_frame.video_frame.stride[0],out_frame.video_frame.phy_addr[0]); if (fp_frm) { fwrite(vaddr, 1, hor_stride * ver_stride * 3 / 2, fp_frm); fflush(fp_frm); } sys_ops->sys_munmap(vaddr, hor_stride * ver_stride * 3 / 2); vdec_chn->release_frame(chn_id, &out_frame); printf("getFrame %dx%d addr %lld\n", out_frame.video_frame.width, out_frame.video_frame.height, out_frame.video_frame.phy_addr[0]); } if (coding_type != QUA_VIDEO_CodingJpeg) { memset(&packet, 0, sizeof(qua_vdec_stream_t)); packet.end_of_stream = QUA_TRUE; vdec_chn->send_stream(chn_id, &packet, -1); } vdec_chn->stop_chn(chn_id); mm_channel->release(mm_channel); vdec_device->parent.close(mm_device); if (fp_strm) fclose(fp_strm); if (fp_frm) fclose(fp_frm); if (pu8_buf) free(pu8_buf); printf("==============qua mm vdec test done============\n"); }