10.1_demo/extern/qlibquammapi/sample/video/enc/qua_venc_sample.c

463 lines
17 KiB
C

/*
* Copyright (c) 2023~2024 Quaming Intelligent Technology Co., Ltd.
*
* All Rights Reserved.
* Confidential and Proprietary - Quaming Intelligent Technology Co., Ltd.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#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 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_cnt -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/h265/jpeg\n");
printf("\t -n --channels : channel of encoder.\n");
printf("\t -d --output : the full path of the output file\n");
}
static qua_venc_type_t get_enc_type(char *stype) {
qua_venc_type_t enc_type = QUA_VENC_TYPE_DUMMY;
if(strcasecmp(stype, "jpeg") == 0) {
enc_type = QUA_JPEG;
} else if(strcasecmp(stype, "h264") == 0) {
enc_type = QUA_NORMAL_H264;
} else if(strcasecmp(stype, "h265") == 0) {
enc_type = QUA_NORMAL_H265;
} else if(strcasecmp(stype, "s264") == 0) {
enc_type = QUA_SMART_H264;
} else if(strcasecmp(stype, "s265") == 0) {
enc_type = QUA_SMART_H265;
}
return enc_type;
}
static void qua_mm_get_sys_ops(const char *platform, QUA_BOOL primary, qua_mm_system_ops_t **sys_ops) {
qua_mm_system_t *system;
qua_mm_system_ops_t *ops;
QUA_U32 blk_size;
qua_vb_config_t vb_cfg;
qua_mm_init(primary, platform, &system);
ops = (qua_mm_system_ops_t *)system;
memset(&vb_cfg, 0, sizeof(qua_vb_config_t));
blk_size = 640*480*2;
vb_cfg.max_pool_cnt = QUA_VB_MAX_POOLS;
vb_cfg.common_pools[0].block_size = blk_size;
vb_cfg.common_pools[0].block_cnt = 6;
if (primary) {
ops->sys_init(&vb_cfg);
}
*sys_ops = ops;
}
void read_yuv(QUA_U32 idx, QUA_U32 width, QUA_U32 height, QUA_U32 stride, void *y_addr, void *uv_addr, FILE *fp) {
QUA_U32 i = 0;
QUA_U32 seek = idx * width * height * 3 / 2;
// copy y
fseek(fp, 0, SEEK_SET);
for(; i < height; i++) {
fseek(fp, seek, SEEK_SET);
fread(y_addr, 1, width, fp);
seek += width;
y_addr += stride;
}
// copy uv
i = 0;
seek = idx * width * height * 3 / 2 + width * height;
for(; i < height / 2; i++) {
fseek(fp, seek, SEEK_SET);
fread(uv_addr, 1, width, fp);
seek += width;
uv_addr += stride;
}
}
int main(int argc, char *argv[]) {
QUA_S32 chn_id;
QUA_S32 ret;
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_U32 vb_cnt = 0;
QUA_U32 width;
QUA_U32 height;
qua_venc_type_t enc_type;
qua_venc_chn_attr_t chn_attr;
qua_venc_chn_cap_t chn_cap;
qua_venc_attr_jpeg_t jpeg_attr;
qua_venc_stream_t packet;
qua_video_frame_info_t frame_info;
int32_t venc_fd;
fd_set venc_read_fds;
struct timeval timeout_val;
struct timeval start;
struct timeval end;
QUA_U64 phy_addr;
QUA_VOID *vir_addr;
QUA_U32 yuv_align_size;
QUA_U32 hor_stride, ver_stride;
QUA_U32 y_align_size;
QUA_BOOL primary;
QUA_U32 i;
QUA_U64 time_stamp = 0;
QUA_U32 encode_cnt = 0;
QUA_BOOL is_jpeg = QUA_FALSE;
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, frame_path, sizeof(frame_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, stream_path, sizeof(stream_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_CODING_FORMAT, tmp_buf, sizeof(tmp_buf));
if (ret == QUA_FAILURE) {
printf("get coding format error!\n");
print_usage(argv[0]);
return ret;
}
enc_type = get_enc_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 venc test============\n");
printf("frame file: %s\n", frame_path);
printf("stream file: %s\n", stream_path);
printf("enc type: %d\n", enc_type);
printf("number of channels: %d\n", chn_id);
printf("vb_cnt: %d\n", vb_cnt);
printf("venc dimention: %d x %d\n", width, height);
fp_frm = fopen(frame_path, "rb");
if (fp_frm == NULL) {
printf("can't open frame %s (%s)\n", frame_path, strerror(errno));
return -1;
}
fp_strm = fopen(stream_path, "wb");
if (fp_strm == NULL) {
printf("can't open stream %s (%s)\n", stream_path, strerror(errno));
}
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_ENC, 0, &mm_device);
if (ret != QUA_SUCCESS || mm_device == NULL)
return -1;
qua_mm_venc_device_t *venc_device = (qua_mm_venc_device_t *)mm_device;
printf("Device %s\n", venc_device->parent.id);
is_jpeg = enc_type == QUA_JPEG;
qua_mm_channel_t *mm_chn;
qua_mm_venc_chn_attr_t attr;
qua_mm_venc_channel_t *venc_chn;
qua_mm_jpege_channel_t *jpege_chn;
if (!is_jpeg) {
chn_cap.support_type = enc_type;
chn_cap.max_size.width = width;
chn_cap.max_size.height = height;
attr.chn_cap = chn_cap;
attr.video_chn = QUA_MM_VIDEO_VENC_CHN;
encode_cnt = 30;
ret = venc_device->parent.create_channel(&venc_device->parent, &chn_id, &attr, &mm_chn);
if (ret != QUA_SUCCESS) {
printf("venc can't create channel %d ret 0x%x\n", chn_id, ret);
goto EXIT;
}
venc_chn = (qua_mm_venc_channel_t *)mm_chn;
qua_venc_chn_attr_t venc_attr;
switch (enc_type) {
case QUA_NORMAL_H264: {
packet.chn_id = chn_id;
packet.stream_type = QUA_STREAM_H264;
venc_attr.venc_attr.enc_type = QUA_NORMAL_H264;
venc_attr.venc_attr.attr_u.attr_h264.profile = QUA_H264_PROFILE_MAIN;
venc_attr.venc_attr.attr_u.attr_h264.i_frame_interval = 50;
venc_attr.venc_attr.attr_u.attr_h264.pic_width = width;
venc_attr.venc_attr.attr_u.attr_h264.pic_height = height;
venc_attr.venc_rc_attr.rc_mode = QUA_VENC_RC_MODE_H264VBR;
venc_attr.venc_rc_attr.attr_h264_vbr.max_bitRate = 8 * 1000 * 1000;
venc_attr.venc_rc_attr.attr_h264_vbr.init_qp = 35;
venc_attr.venc_rc_attr.attr_h264_vbr.max_iqp = 50;
venc_attr.venc_rc_attr.attr_h264_vbr.min_iqp = 28;
venc_attr.venc_rc_attr.attr_h264_vbr.max_qp = 50;
venc_attr.venc_rc_attr.attr_h264_vbr.min_qp = 28;
venc_attr.venc_rc_attr.attr_h264_vbr.src_frmrate = 30;
venc_attr.venc_rc_attr.attr_h264_vbr.max_rate_percent = 200;
venc_attr.venc_rc_attr.attr_h264_vbr.i_frm_max_bits = 0;
venc_attr.venc_rc_attr.attr_h264_vbr.ip_qp_delta = 5;
venc_attr.venc_rc_attr.attr_h264_vbr.i_bit_prop = 15;
venc_attr.venc_rc_attr.attr_h264_vbr.p_bit_prop = 1;
venc_attr.venc_rc_attr.attr_h264_vbr.fluctuate_level = 0;
} break;
case QUA_NORMAL_H265: {
packet.chn_id = chn_id;
packet.stream_type = QUA_STREAM_H265;
venc_attr.venc_attr.enc_type = QUA_NORMAL_H265;
venc_attr.venc_attr.attr_u.attr_h265.profile = QUA_H265_PROFILE_MAIN;
venc_attr.venc_attr.attr_u.attr_h265.i_frame_interval = 50;
venc_attr.venc_attr.attr_u.attr_h265.pic_width = width;
venc_attr.venc_attr.attr_u.attr_h265.pic_height = height;
venc_attr.venc_rc_attr.rc_mode = QUA_VENC_RC_MODE_H265VBR;
venc_attr.venc_rc_attr.attr_h265_vbr.max_bitRate = 8 * 1000 * 1000;
venc_attr.venc_rc_attr.attr_h265_vbr.init_qp = 35;
venc_attr.venc_rc_attr.attr_h265_vbr.max_iqp = 50;
venc_attr.venc_rc_attr.attr_h265_vbr.min_iqp = 28;
venc_attr.venc_rc_attr.attr_h265_vbr.max_qp = 50;
venc_attr.venc_rc_attr.attr_h265_vbr.min_qp = 28;
venc_attr.venc_rc_attr.attr_h265_vbr.src_frmrate = 30;
venc_attr.venc_rc_attr.attr_h265_vbr.max_rate_percent = 200;
venc_attr.venc_rc_attr.attr_h265_vbr.i_frm_max_bits = 0;
venc_attr.venc_rc_attr.attr_h265_vbr.ip_qp_delta = 5;
venc_attr.venc_rc_attr.attr_h265_vbr.i_bit_prop = 15;
venc_attr.venc_rc_attr.attr_h265_vbr.p_bit_prop = 1;
venc_attr.venc_rc_attr.attr_h265_vbr.fluctuate_level = 0;
} break;
default:
break;
}
ret = venc_chn->set_chn_attr(chn_id, &venc_attr);
if (ret != QUA_SUCCESS) {
printf("venc set_chn_attr %d failed ret 0x%x\n", chn_id, ret);
goto EXIT;
}
} else {
chn_attr.venc_attr.enc_type = enc_type;
jpeg_attr.max_pic_width = width;
jpeg_attr.max_pic_height = height;
jpeg_attr.pic_width = width;
jpeg_attr.pic_height = height;
jpeg_attr.stream_buf_size = width * height;
jpeg_attr.by_frame = QUA_TRUE;
jpeg_attr.support_dcf = QUA_FALSE;
memcpy(&chn_attr.venc_attr.attr_u.jpeg_u.attr_jpeg, &jpeg_attr, sizeof(qua_venc_attr_jpeg_t));
attr.chn_attr = chn_attr;
attr.video_chn = QUA_MM_VIDEO_JPEGE_CHN;
encode_cnt = 1;
qua_mm_channel_t *mm_chn;
ret = venc_device->parent.create_channel(&venc_device->parent, &chn_id, &attr, &mm_chn);
if (ret != QUA_SUCCESS) {
printf("venc can't create channel %d ret 0x%x\n", chn_id, ret);
goto EXIT;
}
jpege_chn = (qua_mm_jpege_channel_t *)mm_chn;
packet.chn_id = chn_id;
packet.stream_type = QUA_STREAM_JPEG;
}
ret = is_jpeg ? jpege_chn->start_recv_pic(chn_id) :
venc_chn->start_recv_pic(chn_id);
if (ret != QUA_SUCCESS) {
printf("venc channel %d start receive picture failed ret 0x%x\n", chn_id, ret);
goto START_FAILED;
}
QUA_U32 align = is_jpeg ? 16 : 64;
hor_stride = ALIGNTO(width, align);
ver_stride = ALIGNTO(height, align);
y_align_size = hor_stride * ver_stride;
yuv_align_size = hor_stride * ver_stride * 3 / 2;
sys_ops->sys_mmz_alloc("test_enc_buffer", NULL, yuv_align_size, &phy_addr, &vir_addr);
for (i = 0; i < encode_cnt; i++) {
memset(&frame_info, 0, sizeof(qua_video_frame_info_t));
frame_info.pool_id = -1;
frame_info.video_frame.width = width;
frame_info.video_frame.height = height;
frame_info.video_frame.field = QUA_VIDOE_FIELD_FRAME;
frame_info.video_frame.pixel_fmt = QUA_PIXEL_FMT_YUV_SEMIPLANAR_420;
frame_info.video_frame.video_fmt = QUA_VIDEO_FORMAT_LINEAR;
frame_info.video_frame.compress_mode = QUA_COMPRESS_MODE_NONE;
frame_info.video_frame.stride[0]= hor_stride;
frame_info.video_frame.phy_addr[0]= phy_addr;
frame_info.video_frame.phy_addr[1]= phy_addr + y_align_size;
frame_info.video_frame.vir_addr[0]= (QUA_U64)vir_addr;
frame_info.video_frame.vir_addr[1]= (QUA_U64)vir_addr + y_align_size;
frame_info.video_frame.pts = time_stamp;
time_stamp += 33333;
printf("read yuv idx %d\n", i);
read_yuv(i, width, height, hor_stride,
frame_info.video_frame.vir_addr[0],
frame_info.video_frame.vir_addr[1],
fp_frm);
ret = is_jpeg ? jpege_chn->send_frame(chn_id, &frame_info, -1) :
venc_chn->send_frame(chn_id, &frame_info, -1);
if (ret != QUA_SUCCESS) {
goto ENCODE_FAILED;
}
gettimeofday(&start, NULL);
if (is_jpeg) {
venc_fd = jpege_chn->get_chn_fd(chn_id);
FD_ZERO(&venc_read_fds);
FD_SET(venc_fd, &venc_read_fds);
timeout_val.tv_sec = 1;
timeout_val.tv_usec = 0;
ret = select(venc_fd + 1, &venc_read_fds, NULL, NULL, &timeout_val);
if (ret <= 0) {
printf("select timeout\n");
goto ENCODE_FAILED;
}
}
ret = is_jpeg ? jpege_chn->get_stream(chn_id, &packet, 0) :
venc_chn->get_stream(chn_id, &packet, 1000);
if (ret != QUA_SUCCESS) {
printf("venc %d get Stream failed ret 0x%x\n", chn_id, ret);
goto ENCODE_FAILED;
}
gettimeofday(&end, NULL);
printf("cost %ld ms\n", (end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000);
if (fp_strm) {
if (enc_type == QUA_JPEG)
fwrite(packet.jpeg_stream.vir_addr, 1, packet.jpeg_stream.length, fp_strm);
else if (enc_type == QUA_NORMAL_H264 || enc_type == QUA_SMART_H264)
fwrite(packet.h264_stream.start, 1, packet.h264_stream.length, fp_strm);
else
fwrite(packet.h265_stream.start, 1, packet.h265_stream.length, fp_strm);
fflush(fp_strm);
}
if (is_jpeg) {
ret = jpege_chn->release_stream(chn_id, &packet);
printf("stream addr 0x%x size %d\n", packet.jpeg_stream.vir_addr, packet.jpeg_stream.length);
} else {
ret = venc_chn->release_stream(chn_id, &packet);
printf("stream chn_id %d addr 0x%x size %d frame type %d nalu cnt %d time_stamp %d\n", packet.chn_id, packet.h264_stream.start,
packet.h264_stream.length, packet.h264_stream.frame_type, packet.h264_stream.nalu_cnt, packet.h264_stream.time_stamp);
}
}
sys_ops->sys_mmz_free(phy_addr, vir_addr);
ENCODE_FAILED:
ret = is_jpeg ? jpege_chn->stop_recv_pic(chn_id) : venc_chn->stop_recv_pic(chn_id);
if (ret != QUA_SUCCESS) {
printf("venc channel %d stop failed ret 0x%x\n", chn_id, ret);
return -1;
}
START_FAILED:
ret = is_jpeg ? jpege_chn->parent.release(&jpege_chn->parent) :
venc_chn->parent.release(&venc_chn->parent);
if (ret != QUA_SUCCESS) {
printf("venc channel %d destroy failed ret 0x%x\n", chn_id, ret);
return -1;
}
venc_device->parent.close(&venc_device->parent);
EXIT:
if (fp_strm)
fclose(fp_strm);
if (fp_frm)
fclose(fp_frm);
printf("==============qua mm venc test done============\n");
}