You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1900 lines
60 KiB
1900 lines
60 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved.
|
|
* Description: encoder sample
|
|
* Author: sdk
|
|
* Create: 2019-08-13
|
|
*/
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include <limits.h>
|
|
|
|
#include "securec.h"
|
|
#include "uapi_system.h"
|
|
#include "uapi_memory.h"
|
|
#include "uapi_venc.h"
|
|
|
|
#undef VENC_PROPERTY_TEST
|
|
#define QFRAME_NUM 6
|
|
#define VENC_MAX_CHN 32
|
|
#define FILE_PATH_LENGTH 128
|
|
#define FILE_NAME_LENGTH 64
|
|
#define FILE_MAX_LENGTH (FILE_PATH_LENGTH + FILE_NAME_LENGTH)
|
|
#define RESOLUTION_ALIGN 16
|
|
#define YUV_8_BIT 1.0f
|
|
#define YUV_10_BIT 1.25f
|
|
#define RETRY_CNT 200
|
|
|
|
#define align_up(val, align) ((((td_u32)(val) + (align) - 1) / (align))*(align))
|
|
|
|
#define venc_err_printf(fmt, args...) printf("%s(%d): " fmt, __func__, __LINE__, ##args)
|
|
|
|
#define DEBUG
|
|
#ifdef DEBUG
|
|
#define venc_warn_printf(fmt, args...) printf("%s(%d): " fmt, __func__, __LINE__, ##args)
|
|
#else
|
|
#define venc_warn_printf(fmt, args...)
|
|
#endif
|
|
|
|
#define sec_chk_neq_ret(func, ret) do { \
|
|
if ((func) != EOK) { \
|
|
venc_err_printf("call %s failed\n", #func); \
|
|
return ret; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define sec_chk_lt_ret(func, ret) do { \
|
|
if ((func) < 0) { \
|
|
venc_err_printf("call %s failed\n", #func); \
|
|
return ret; \
|
|
} \
|
|
} while (0)
|
|
|
|
typedef struct {
|
|
td_u32 real_chn_num;
|
|
td_handle chan_id[VENC_MAX_CHN];
|
|
FILE *file_input[VENC_MAX_CHN];
|
|
FILE *file_output[VENC_MAX_CHN];
|
|
td_u32 pic_width[VENC_MAX_CHN];
|
|
td_u32 pic_height[VENC_MAX_CHN];
|
|
td_u32 time_out[VENC_MAX_CHN];
|
|
} sample_thread_info;
|
|
|
|
typedef struct {
|
|
td_u32 real_chn_num;
|
|
td_handle chan_id;
|
|
FILE *file_enc;
|
|
td_u32 width;
|
|
td_u32 height;
|
|
td_u32 index;
|
|
} queue_thread_info;
|
|
|
|
typedef enum {
|
|
VCODE_TYPE_H264 = 0,
|
|
VCODE_TYPE_MJPEG,
|
|
VCODE_TYPE_JPEG,
|
|
VCODE_TYPE_H265,
|
|
VCODE_TYPE_MAX
|
|
} sample_vcode_type;
|
|
|
|
enum {
|
|
CMD_CONTINUE = -1,
|
|
CMD_CHANGE_INPUT_FPS = 0,
|
|
CMD_CHANGE_TARGET_FPS,
|
|
CMD_CHANGE_BITRATE,
|
|
CMD_CHANGE_GOP,
|
|
CMD_CHANGE_MAX_QP,
|
|
CMD_CHANGE_MIN_QP,
|
|
CMD_CHANGE_PRIORITY,
|
|
CMD_EXIT
|
|
};
|
|
|
|
static pthread_t g_thread_send_frame[VENC_MAX_CHN];
|
|
queue_thread_info g_send_frame_info[VENC_MAX_CHN];
|
|
static td_bool g_send_frame_stop = TD_FALSE;
|
|
|
|
static td_handle g_venc_chan_id[VENC_MAX_CHN];
|
|
|
|
static td_char g_input_file_names[VENC_MAX_CHN][FILE_MAX_LENGTH];
|
|
static td_char g_output_file_names[VENC_MAX_CHN][FILE_MAX_LENGTH];
|
|
static td_u32 g_jpeg_save_type[VENC_MAX_CHN] = {0};
|
|
|
|
uapi_mem_buf g_frame_buf[VENC_MAX_CHN][QFRAME_NUM];
|
|
|
|
typedef struct {
|
|
td_handle chan_id;
|
|
FILE *file_save;
|
|
td_u32 time_out;
|
|
td_char file_name[FILE_MAX_LENGTH];
|
|
} save_stream_thread_info;
|
|
|
|
static pthread_t g_thread_save_stream[VENC_MAX_CHN];
|
|
static save_stream_thread_info g_save_stream_info[VENC_MAX_CHN];
|
|
static td_bool g_save_stream_stop = TD_FALSE;
|
|
static td_s32 g_yuv_store_type = 0;
|
|
static float g_yuv_bit_deep = YUV_8_BIT;
|
|
|
|
typedef struct {
|
|
td_u32 pic_width;
|
|
td_u32 pic_height;
|
|
td_u32 enc_width;
|
|
td_u32 enc_height;
|
|
} src_input_info;
|
|
|
|
static td_void get_file_path(const td_char *file_name, td_char *path, td_s32 path_len, td_char *name, td_s32 name_len)
|
|
{
|
|
td_u32 file_name_len = strlen(file_name);
|
|
td_s32 i = file_name_len;
|
|
td_s32 cur_path_len, cur_name_len;
|
|
|
|
if (path_len < 3) { /* 3: min path "./" */
|
|
printf("path len too small!\n");
|
|
return;
|
|
}
|
|
|
|
while (i > 0) {
|
|
if (file_name[i] == '/') {
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
|
|
cur_path_len = (i > 0) ? (i + 1) : 3; /* 2: "/" + '/0' 3: "./" len */
|
|
cur_name_len = file_name_len - i + 1;
|
|
|
|
if (i > 0 && cur_path_len < path_len && cur_name_len < name_len) {
|
|
const td_char *cur_name = file_name + i;
|
|
if (strncpy_s(path, path_len, file_name, i) != EOK) {
|
|
printf("strncpy_s file path failed!");
|
|
return;
|
|
}
|
|
path[i] = '\0';
|
|
|
|
if (strncpy_s(name, name_len, cur_name, file_name_len - i) != EOK) {
|
|
printf("strncpy_s file path failed!");
|
|
return;
|
|
}
|
|
name[cur_name_len - 1] = '\0';
|
|
} else {
|
|
if (strncpy_s(path, path_len, "./", 3) != EOK) { /* 3: "./" len */
|
|
printf("strncpy_s file path failed!");
|
|
return;
|
|
}
|
|
|
|
if (strncpy_s(name, name_len, "/", 2) != EOK) { /* 2: "/" len */
|
|
printf("strncpy_s file path failed!");
|
|
return;
|
|
}
|
|
|
|
if (strncat_s(name, name_len, file_name, cur_name_len) != EOK) {
|
|
printf("strncat_s file path failed!");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_void write_bit_stream_to_file(FILE *file, const uapi_venc_stream *venc_stream)
|
|
{
|
|
td_u32 size;
|
|
|
|
if (venc_stream->buf.size > 0) {
|
|
size = (td_u32)fwrite(venc_stream->buf.data, 1, venc_stream->buf.size, file);
|
|
if (size != venc_stream->buf.size) {
|
|
venc_err_printf("fwrite err0, write size=%d, slclen=%d\n", size, venc_stream->buf.size);
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_void *sample_save_stream_process(td_void *args)
|
|
{
|
|
save_stream_thread_info *thread_info = (save_stream_thread_info *)args;
|
|
|
|
td_s32 ret;
|
|
uapi_venc_stream venc_stream;
|
|
|
|
while (!g_save_stream_stop) {
|
|
ret = uapi_venc_acquire_stream(thread_info->chan_id, &venc_stream, thread_info->time_out);
|
|
if (ret != TD_SUCCESS) {
|
|
usleep(2 * 1000); /* 2, 1000: 2ms */
|
|
continue;
|
|
}
|
|
|
|
if (thread_info->file_save != TD_NULL) { /* save to file */
|
|
write_bit_stream_to_file(thread_info->file_save, &venc_stream);
|
|
} else {
|
|
printf("ERROR: the pFie is NULL!!\n");
|
|
}
|
|
|
|
ret = uapi_venc_release_stream(thread_info->chan_id, &venc_stream);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("uapi_venc_release_stream failed, u32Ret=%x\n", ret);
|
|
}
|
|
}
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_void *sample_save_stream_process_mjpeg(td_void *args)
|
|
{
|
|
save_stream_thread_info *thread_info = (save_stream_thread_info *)args;
|
|
|
|
td_s32 ret;
|
|
td_u32 size;
|
|
uapi_venc_stream venc_stream;
|
|
td_handle chan_id = thread_info->chan_id;
|
|
FILE *file = thread_info->file_save;
|
|
while (!g_save_stream_stop) {
|
|
sec_chk_neq_ret(memset_s(&venc_stream, sizeof(uapi_venc_stream), 0, sizeof(uapi_venc_stream)), TD_NULL);
|
|
|
|
ret = uapi_venc_acquire_stream(chan_id, &venc_stream, 0);
|
|
if (ret != TD_SUCCESS) {
|
|
usleep(3 * 1000); /* 3, 1000: 3ms */
|
|
continue;
|
|
}
|
|
|
|
if (file != TD_NULL) { /* save to file */
|
|
size = venc_stream.buf.size;
|
|
fwrite(&size, 1, sizeof(td_u32), file);
|
|
write_bit_stream_to_file(file, &venc_stream);
|
|
} else {
|
|
printf("ERROR: the pFie is NULL!!\n");
|
|
}
|
|
|
|
uapi_venc_release_stream(chan_id, &venc_stream);
|
|
}
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_u32 g_jpeg_num = 0;
|
|
|
|
static td_void save_stream_to_file(const save_stream_thread_info *thread_info, const uapi_venc_stream *venc_stream)
|
|
{
|
|
td_s32 name_len;
|
|
td_char file_name[FILE_MAX_LENGTH] = {0};
|
|
td_char name[FILE_NAME_LENGTH] = {0};
|
|
td_char path[FILE_PATH_LENGTH] = {0};
|
|
td_char file_id[FILE_NAME_LENGTH];
|
|
td_char real_path[PATH_MAX] = {0};
|
|
FILE *file = TD_NULL;
|
|
|
|
if (memcpy_s(file_name, sizeof(file_name), thread_info->file_name, sizeof(thread_info->file_name)) != EOK) {
|
|
printf("memcpy failed\n");
|
|
return;
|
|
}
|
|
if (snprintf_s(file_id, sizeof(file_id), sizeof(file_id) - 1, "_%d.jpg", g_jpeg_num) < 0) {
|
|
printf("snprintf_s failed\n");
|
|
return;
|
|
}
|
|
if (strncat_s(file_name, sizeof(file_name), file_id, strlen(file_id)) != EOK) {
|
|
printf("strncat_s failed\n");
|
|
return;
|
|
}
|
|
|
|
get_file_path(file_name, path, FILE_PATH_LENGTH, name, FILE_NAME_LENGTH);
|
|
name_len = strlen(name) + 1;
|
|
if (realpath(path, real_path) != TD_NULL) {
|
|
if (strncat_s(real_path, PATH_MAX, name, name_len) != EOK) {
|
|
return;
|
|
}
|
|
file = fopen(real_path, "wb+");
|
|
if (file != TD_NULL) { /* save to file */
|
|
write_bit_stream_to_file(file, venc_stream);
|
|
} else {
|
|
printf("ERROR: the pFie is NULL!!\n");
|
|
}
|
|
g_jpeg_num++;
|
|
if (g_jpeg_num >= 9999) { /* 9999: max jpeg number */
|
|
g_jpeg_num = 0;
|
|
}
|
|
} else {
|
|
venc_err_printf("get real path %s failed\n", file_name);
|
|
}
|
|
|
|
if (file != TD_NULL) {
|
|
fclose(file);
|
|
file = TD_NULL;
|
|
}
|
|
}
|
|
|
|
static td_void *sample_save_stream_process_jpeg(td_void *args)
|
|
{
|
|
save_stream_thread_info *thread_info = (save_stream_thread_info *)args;
|
|
|
|
uapi_venc_stream venc_stream;
|
|
td_handle chan_id = thread_info->chan_id;
|
|
|
|
while (!g_save_stream_stop) {
|
|
(td_void)memset_s(&venc_stream, sizeof(uapi_venc_stream), 0, sizeof(uapi_venc_stream));
|
|
|
|
if (uapi_venc_acquire_stream(chan_id, &venc_stream, 0) != TD_SUCCESS) {
|
|
usleep(3 * 1000); /* 3, 1000: 3ms */
|
|
continue;
|
|
}
|
|
|
|
save_stream_to_file(thread_info, &venc_stream);
|
|
|
|
uapi_venc_release_stream(chan_id, &venc_stream);
|
|
}
|
|
return TD_NULL;
|
|
}
|
|
|
|
enum {
|
|
YUV_SEMIPLANNER_420_UV = 0,
|
|
YUV_SEMIPLANNER_420_VU,
|
|
YUV_PLANNER_420,
|
|
YUV_PACKAGE_422_YUYV,
|
|
YUV_PACKAGE_422_YVYU,
|
|
YUV_PACKAGE_422_UYVY,
|
|
COLOR_CHANNEL_ARGB_8888,
|
|
YUV_SEMIPLANNER_420_UV_10BIT,
|
|
YUV_SEMIPLANNER_420_VU_10BIT,
|
|
YUV_SEMIPLANNER_422_UV, /* not support */
|
|
YUV_SEMIPLANNER_422_VU, /* not support */
|
|
YUV_UNKNOW_BUIT
|
|
};
|
|
|
|
enum {
|
|
V_U = 0,
|
|
U_V = 1
|
|
};
|
|
|
|
enum {
|
|
SAMPLE_VEDU_ARGB = 0,
|
|
SAMPLE_VEDU_UY0VY1 = 0x8d,
|
|
SAMPLE_VEDU_Y0UY1V = 0xd8,
|
|
SAMPLE_VEDU_Y0VY1U = 0x78
|
|
};
|
|
|
|
typedef enum {
|
|
SAMPLE_VEDU_YUV420 = 0,
|
|
SAMPLE_VEDU_YUV422,
|
|
SAMPLE_VEDU_YUV444,
|
|
SAMPLE_VEDU_COLOR_CHANNEL
|
|
} vedu_yuv_sample;
|
|
|
|
typedef enum {
|
|
SAMPLE_VEDU_SEMIPLANNAR = 0,
|
|
SAMPLE_VEDU_PACKAGE,
|
|
SAMPLE_VEDU_PLANNAR
|
|
} vedu_yuv_store;
|
|
|
|
#define READ_ERROR (-2)
|
|
|
|
typedef struct {
|
|
td_u32 width;
|
|
td_u32 height;
|
|
td_u32 y_stride; /* only by semiplannar, plannar, package */
|
|
td_u32 c_stride; /* only by semiplannar, plannar */
|
|
td_u8 *y_addr; /* only by plannar, semiplannar, package */
|
|
td_u8 *c_addr; /* only by plannar, semiplannar */
|
|
td_u8 *v_addr; /* only by plannar */
|
|
td_u32 y_size;
|
|
td_u32 c_size;
|
|
td_u32 v_size;
|
|
vedu_yuv_sample sample; /* 420 422 444 */
|
|
vedu_yuv_store store; /* semiplannar, plannar, package */
|
|
td_u32 sel;
|
|
} sample_yuv_info;
|
|
|
|
static td_s32 get_c_width_height_by_sample(td_u32 *c_width, td_u32 *c_height, sample_yuv_info *yuv_info)
|
|
{
|
|
if (yuv_info->sample == SAMPLE_VEDU_YUV420) {
|
|
*c_width = yuv_info->width >> 1;
|
|
*c_height = yuv_info->height >> 1;
|
|
} else if (yuv_info->sample == SAMPLE_VEDU_YUV422) {
|
|
*c_width = yuv_info->width >> 1;
|
|
*c_height = yuv_info->height >> 0;
|
|
} else if (yuv_info->sample == SAMPLE_VEDU_YUV444) {
|
|
*c_width = yuv_info->width >> 0;
|
|
*c_height = yuv_info->height >> 0;
|
|
} else {
|
|
venc_err_printf("Unsupported sampling format(%d)\n", yuv_info->sample);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 read_yuv_to_mem_planner(sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_u32 c_width, c_height;
|
|
td_u32 y_width = yuv_info->width;
|
|
td_u32 y_height = yuv_info->height;
|
|
td_s32 ret, j;
|
|
|
|
td_u8 *y_ptr = yuv_info->y_addr;
|
|
td_u8 *u_ptr = yuv_info->c_addr;
|
|
td_u8 *v_ptr = yuv_info->v_addr;
|
|
|
|
ret = get_c_width_height_by_sample(&c_width, &c_height, yuv_info);
|
|
if (ret != TD_SUCCESS) {
|
|
venc_err_printf("get_c_width_height_by_sample failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (j = 0; j < (td_s32)y_height; j++, y_ptr += yuv_info->y_stride) {
|
|
if (fread(y_ptr, y_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
for (j = 0; j < (td_s32)c_height; j++, u_ptr += yuv_info->c_stride) {
|
|
if (fread(u_ptr, c_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
for (j = 0; j < (td_s32)c_height; j++, v_ptr += yuv_info->c_stride) {
|
|
if (fread(v_ptr, c_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
|
|
exit:
|
|
printf("error:read yuv\n");
|
|
return READ_ERROR;
|
|
}
|
|
|
|
static td_s32 copy_uv_to_mem(sample_yuv_info *yuv_info, td_u32 c_width, td_u32 c_height)
|
|
{
|
|
td_s32 t0 = yuv_info->sel & 1;
|
|
const td_s32 t1 = 1 - t0;
|
|
td_u8 *u_ptr = yuv_info->c_addr;
|
|
td_u8 *v_ptr = yuv_info->c_addr + yuv_info->c_stride / 2; /* 2: yuv store formal */
|
|
td_s32 j, i;
|
|
td_u8 *uv_ptr;
|
|
|
|
if ((uv_ptr = (td_u8 *)malloc(yuv_info->c_stride)) == TD_NULL) {
|
|
venc_err_printf("error: malloc @ read yuv\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (j = 0; j < (td_s32)c_height; j++, u_ptr += yuv_info->c_stride, v_ptr += yuv_info->c_stride) {
|
|
for (i = 0; i < (td_s32)c_width; i++) {
|
|
uv_ptr[i * 2 + t0] = *(v_ptr + i); /* 2: yuv store formal */
|
|
uv_ptr[i * 2 + t1] = *(u_ptr + i); /* 2: yuv store formal */
|
|
}
|
|
|
|
if (memcpy_s(u_ptr, yuv_info->c_size, uv_ptr, 2 * c_width) != EOK) { /* 2: yuv store formal */
|
|
venc_err_printf("memcpy failed\n");
|
|
free(uv_ptr);
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
free(uv_ptr);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 read_yuv_to_mem_semi(sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_u32 c_width, c_height;
|
|
td_u32 y_width = yuv_info->width;
|
|
td_u32 y_height = yuv_info->height;
|
|
td_s32 j;
|
|
|
|
td_u8 *y_ptr = yuv_info->y_addr;
|
|
td_u8 *u_ptr = yuv_info->c_addr;
|
|
td_u8 *v_ptr = yuv_info->v_addr;
|
|
|
|
if (get_c_width_height_by_sample(&c_width, &c_height, yuv_info) != TD_SUCCESS) {
|
|
venc_err_printf("get_c_width_height_by_sample failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
v_ptr = yuv_info->c_addr + yuv_info->c_stride / 2; /* 2: yuv store formal */
|
|
for (j = 0; j < (td_s32)y_height; j++, y_ptr += yuv_info->y_stride) {
|
|
if (fread(y_ptr, y_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
for (j = 0; j < (td_s32)c_height; j++, u_ptr += yuv_info->c_stride) {
|
|
if (fread(u_ptr, c_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
for (j = 0; j < (td_s32)c_height; j++, v_ptr += yuv_info->c_stride) {
|
|
if (fread(v_ptr, c_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (copy_uv_to_mem(yuv_info, c_width, c_height) != TD_SUCCESS) {
|
|
venc_err_printf("copy_uv_to_mem failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
exit:
|
|
printf("error:read yuv\n");
|
|
return READ_ERROR;
|
|
}
|
|
|
|
static td_s32 read_uv_to_mem_package420(td_u8 *uv_ptr, sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_u32 c_width, c_height;
|
|
td_s32 j, i;
|
|
td_u8 *u_ptr = yuv_info->c_addr;
|
|
td_u8 *v_ptr = yuv_info->v_addr;
|
|
|
|
td_s32 u0_sel = (yuv_info->sel >> 4) & 3; /* 4, 3: yuv store formal */
|
|
td_s32 v0_sel = (yuv_info->sel >> 6) & 3; /* 6, 3: yuv store formal */
|
|
|
|
if (get_c_width_height_by_sample(&c_width, &c_height, yuv_info) != TD_SUCCESS) {
|
|
venc_err_printf("get_c_width_height_by_sample failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
u_ptr = yuv_info->y_addr + u0_sel;
|
|
for (j = 0; j < (td_s32)c_height; j++, u_ptr += yuv_info->y_stride * 2) { /* 2: yuv store formal */
|
|
if (fread(uv_ptr, c_width, 1, yuv_file) != 1) {
|
|
return READ_ERROR;
|
|
}
|
|
|
|
for (i = c_width - 1; i >= 0; i--) {
|
|
*(u_ptr + i * 4) = *(uv_ptr + i); /* 4: yuv store formal */
|
|
}
|
|
}
|
|
|
|
v_ptr = yuv_info->y_addr + v0_sel;
|
|
for (j = 0; j < (td_s32)c_height; j++, v_ptr += yuv_info->y_stride * 2) { /* 2: yuv store formal */
|
|
if (fread(uv_ptr, c_width, 1, yuv_file) != 1) {
|
|
return READ_ERROR;
|
|
}
|
|
|
|
for (i = c_width - 1; i >= 0; i--) {
|
|
*(v_ptr + i * 4) = *(uv_ptr + i); /* 4: yuv store formal */
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
|
|
static td_s32 read_yuv_to_mem_package420(sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_s32 j, i;
|
|
td_u32 y_width = yuv_info->width;
|
|
td_u32 y_height = yuv_info->height;
|
|
|
|
td_u8 *uv_ptr;
|
|
td_u8 *y_ptr = yuv_info->y_addr;
|
|
|
|
td_s32 y0_sel = (yuv_info->sel >> 0) & 3; /* 0, 3: yuv store formal */
|
|
td_s32 y1_sel = (yuv_info->sel >> 2) & 3; /* 2, 3: yuv store formal */
|
|
|
|
if ((uv_ptr = (td_u8 *)malloc(y_width)) == TD_NULL) {
|
|
venc_err_printf("error: malloc @ read yuv\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (j = 0; j < (td_s32)y_height; j++, y_ptr += yuv_info->y_stride) {
|
|
if (fread(uv_ptr, y_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
|
|
for (i = y_width / 2 - 1; i >= 0; i--) { /* 2: yuv store formal */
|
|
*(y_ptr + i * 4 + y0_sel) = *(uv_ptr + i * 2); /* 2, 4: yuv store formal */
|
|
*(y_ptr + i * 4 + y1_sel) = *(uv_ptr + i * 2 + 1); /* 2, 4: yuv store formal */
|
|
}
|
|
}
|
|
|
|
if (read_uv_to_mem_package420(uv_ptr, yuv_info, yuv_file) != TD_SUCCESS) {
|
|
goto exit;
|
|
}
|
|
|
|
free(uv_ptr);
|
|
return TD_SUCCESS;
|
|
|
|
exit:
|
|
printf("error:read yuv\n");
|
|
free(uv_ptr);
|
|
return READ_ERROR;
|
|
}
|
|
|
|
static td_s32 read_uv_to_mem_package42x(td_u8 *uv_ptr, sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_u32 c_width, c_height;
|
|
td_u8 *u_ptr = yuv_info->c_addr;
|
|
td_u8 *v_ptr = yuv_info->v_addr;
|
|
td_s32 i, j;
|
|
|
|
td_s32 u0_sel = (yuv_info->sel >> 4) & 3; /* 4, 3: yuv store formal */
|
|
td_s32 v0_sel = (yuv_info->sel >> 6) & 3; /* 6, 3: yuv store formal */
|
|
|
|
if (get_c_width_height_by_sample(&c_width, &c_height, yuv_info) != TD_SUCCESS) {
|
|
venc_err_printf("get_c_width_height_by_sample failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
u_ptr = yuv_info->y_addr + u0_sel;
|
|
for (j = 0; j < (td_s32)c_height; j++, u_ptr += yuv_info->y_stride) {
|
|
if (j % 2 == 0) { /* 2: yuv store formal */
|
|
if (fread(uv_ptr, c_width, 1, yuv_file) != 1) {
|
|
return READ_ERROR;
|
|
}
|
|
}
|
|
|
|
for (i = c_width - 1; i >= 0; i--) {
|
|
*(u_ptr + i * 4) = *(uv_ptr + i); /* 4: yuv store formal */
|
|
}
|
|
}
|
|
|
|
v_ptr = yuv_info->y_addr + v0_sel;
|
|
for (j = 0; j < (td_s32)c_height; j++, v_ptr += yuv_info->y_stride) {
|
|
if (j % 2 == 0) { /* 2: yuv store formal */
|
|
if (fread(uv_ptr, c_width, 1, yuv_file) != 1) {
|
|
return READ_ERROR;
|
|
}
|
|
}
|
|
|
|
for (i = c_width - 1; i >= 0; i--) {
|
|
*(v_ptr + i * 4) = *(uv_ptr + i); /* 4: yuv store formal */
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 read_yuv_to_mem_package42x(sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_s32 j, i;
|
|
td_u32 y_width = yuv_info->width;
|
|
td_u32 y_height = yuv_info->height;
|
|
|
|
td_u8 *uv_ptr;
|
|
td_u8 *y_ptr = yuv_info->y_addr;
|
|
|
|
td_s32 y0_sel = (yuv_info->sel >> 0) & 3; /* 0, 3: yuv store formal */
|
|
td_s32 y1_sel = (yuv_info->sel >> 2) & 3; /* 2, 3: yuv store formal */
|
|
|
|
if ((uv_ptr = (td_u8 *)malloc(y_width)) == TD_NULL) {
|
|
venc_err_printf("error: malloc @ read yuv\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (j = 0; j < (td_s32)y_height; j++, y_ptr += yuv_info->y_stride) {
|
|
if (fread(uv_ptr, y_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
|
|
if (yuv_info->sample == SAMPLE_VEDU_YUV422) {
|
|
for (i = y_width / 2 - 1; i >= 0; i--) { /* 2: yuv store formal */
|
|
*(y_ptr + i * 4 + y0_sel) = *(uv_ptr + i * 2); /* 2, 4: yuv store formal */
|
|
*(y_ptr + i * 4 + y1_sel) = *(uv_ptr + i * 2 + 1); /* 2, 4: yuv store formal */
|
|
}
|
|
} else {
|
|
for (i = y_width - 1; i >= 0; i--) {
|
|
*(y_ptr + i * 4 + y0_sel) = *(uv_ptr + i); /* 4: yuv store formal */
|
|
}
|
|
}
|
|
}
|
|
|
|
if (read_uv_to_mem_package42x(uv_ptr, yuv_info, yuv_file) != TD_SUCCESS) {
|
|
goto exit;
|
|
}
|
|
|
|
free(uv_ptr);
|
|
return TD_SUCCESS;
|
|
|
|
exit:
|
|
printf("error:read yuv\n");
|
|
free(uv_ptr);
|
|
return READ_ERROR;
|
|
}
|
|
|
|
static td_s32 read_yuv_to_mem_package(sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_s32 ret;
|
|
|
|
if (yuv_info->sample == SAMPLE_VEDU_YUV420) {
|
|
ret = read_yuv_to_mem_package420(yuv_info, yuv_file);
|
|
} else if (yuv_info->sample == SAMPLE_VEDU_YUV422) {
|
|
ret = read_yuv_to_mem_package42x(yuv_info, yuv_file);
|
|
} else {
|
|
venc_err_printf("unsupport sample type: %d\n", yuv_info->sample);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 yuvfile_to_memory(sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_s32 ret;
|
|
|
|
if (yuv_info->store == SAMPLE_VEDU_PLANNAR) {
|
|
ret = read_yuv_to_mem_planner(yuv_info, yuv_file);
|
|
if (ret == TD_FAILURE) {
|
|
venc_err_printf("read_yuv_to_mem_planner failed\n");
|
|
}
|
|
} else if (yuv_info->store == SAMPLE_VEDU_SEMIPLANNAR) {
|
|
ret = read_yuv_to_mem_semi(yuv_info, yuv_file);
|
|
if (ret == TD_FAILURE) {
|
|
venc_err_printf("read_yuv_to_mem_semi failed\n");
|
|
}
|
|
} else if (yuv_info->store == SAMPLE_VEDU_PACKAGE) {
|
|
ret = read_yuv_to_mem_package(yuv_info, yuv_file);
|
|
if (ret == TD_FAILURE) {
|
|
venc_err_printf("read_yuv_to_mem_package failed\n");
|
|
}
|
|
} else {
|
|
venc_err_printf("unsupported yuv store type: %d\n", yuv_info->store);
|
|
ret = TD_FAILURE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static td_void set_yuv_info_semi_420_uv(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
td_s32 offset_y_cb;
|
|
|
|
yuv_info->y_stride = align_up(thread_info->width * g_yuv_bit_deep, RESOLUTION_ALIGN);
|
|
yuv_info->c_stride = yuv_info->y_stride;
|
|
offset_y_cb = yuv_info->y_stride * thread_info->height;
|
|
yuv_info->sample = SAMPLE_VEDU_YUV420;
|
|
yuv_info->store = SAMPLE_VEDU_SEMIPLANNAR;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = yuv_info->y_addr + offset_y_cb;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = offset_y_cb;
|
|
yuv_info->c_size = buf_size - offset_y_cb;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = U_V;
|
|
}
|
|
|
|
static td_void set_yuv_info_semi_420_vu(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
td_s32 offset_y_cb;
|
|
|
|
yuv_info->y_stride = align_up(thread_info->width * g_yuv_bit_deep, RESOLUTION_ALIGN);
|
|
yuv_info->c_stride = yuv_info->y_stride;
|
|
offset_y_cb = yuv_info->y_stride * thread_info->height;
|
|
yuv_info->sample = SAMPLE_VEDU_YUV420;
|
|
yuv_info->store = SAMPLE_VEDU_SEMIPLANNAR;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = yuv_info->y_addr + offset_y_cb;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = offset_y_cb;
|
|
yuv_info->c_size = buf_size - offset_y_cb;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = V_U;
|
|
}
|
|
|
|
static td_void set_yuv_info_planner_420(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
td_s32 offset_y_cb;
|
|
td_s32 offset_y_cr;
|
|
|
|
yuv_info->y_stride = align_up(thread_info->width, 16);
|
|
yuv_info->c_stride = align_up(thread_info->width / 2, 16);
|
|
offset_y_cb = yuv_info->y_stride * thread_info->height;
|
|
offset_y_cr = yuv_info->c_stride * thread_info->height / 2; /* 2: yuv store formal */
|
|
yuv_info->sample = SAMPLE_VEDU_YUV420;
|
|
yuv_info->store = SAMPLE_VEDU_PLANNAR;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = yuv_info->y_addr + offset_y_cb;
|
|
yuv_info->v_addr = yuv_info->c_addr + offset_y_cr;
|
|
yuv_info->y_size = offset_y_cb;
|
|
yuv_info->c_size = offset_y_cr;
|
|
yuv_info->v_size = buf_size - offset_y_cb - offset_y_cr;
|
|
|
|
yuv_info->sel = 0;
|
|
}
|
|
|
|
static td_void set_yuv_info_semi_422_uv(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
td_s32 offset_y_cb;
|
|
|
|
yuv_info->y_stride = align_up(thread_info->width, 16);
|
|
yuv_info->c_stride = align_up(thread_info->width, 16);
|
|
offset_y_cb = yuv_info->y_stride * thread_info->height;
|
|
yuv_info->sample = SAMPLE_VEDU_YUV422;
|
|
yuv_info->store = SAMPLE_VEDU_SEMIPLANNAR;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = yuv_info->y_addr + offset_y_cb;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = offset_y_cb;
|
|
yuv_info->c_size = buf_size - offset_y_cb;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = U_V;
|
|
}
|
|
|
|
static td_void set_yuv_info_semi_422_vu(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
td_s32 offset_y_cb;
|
|
|
|
yuv_info->y_stride = align_up(thread_info->width, 16);
|
|
yuv_info->c_stride = align_up(thread_info->width, 16);
|
|
offset_y_cb = yuv_info->y_stride * thread_info->height;
|
|
yuv_info->sample = SAMPLE_VEDU_YUV422;
|
|
yuv_info->store = SAMPLE_VEDU_SEMIPLANNAR;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = yuv_info->y_addr + offset_y_cb;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = offset_y_cb;
|
|
yuv_info->c_size = buf_size - offset_y_cb;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = V_U;
|
|
}
|
|
|
|
static td_void set_yuv_info_package_422_yuyv(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
yuv_info->y_stride = align_up(thread_info->width * 2, 16);
|
|
yuv_info->c_stride = 0; // ??
|
|
yuv_info->sample = SAMPLE_VEDU_YUV422;
|
|
yuv_info->store = SAMPLE_VEDU_PACKAGE;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = TD_NULL;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = buf_size;
|
|
yuv_info->c_size = 0;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = SAMPLE_VEDU_Y0UY1V; // ??
|
|
}
|
|
|
|
static td_void set_yuv_info_package_422_yvyu(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
yuv_info->y_stride = align_up(thread_info->width * 2, 16);
|
|
yuv_info->c_stride = 0; // ??
|
|
yuv_info->sample = SAMPLE_VEDU_YUV422;
|
|
yuv_info->store = SAMPLE_VEDU_PACKAGE;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = TD_NULL;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = buf_size;
|
|
yuv_info->c_size = 0;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = SAMPLE_VEDU_Y0VY1U; // ??
|
|
}
|
|
|
|
static td_void set_yuv_info_package_422_uyvy(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
yuv_info->y_stride = align_up(thread_info->width * 2, 16);
|
|
yuv_info->c_stride = 0; // ??
|
|
yuv_info->sample = SAMPLE_VEDU_YUV422;
|
|
yuv_info->store = SAMPLE_VEDU_PACKAGE;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = TD_NULL;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = buf_size;
|
|
yuv_info->c_size = 0;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = SAMPLE_VEDU_UY0VY1; // ??
|
|
}
|
|
|
|
static td_void set_yuv_info_argb_8888(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
yuv_info->y_stride = align_up(thread_info->width * 4, RESOLUTION_ALIGN); /* 4: argb */
|
|
yuv_info->c_stride = 0;
|
|
yuv_info->sample = SAMPLE_VEDU_COLOR_CHANNEL;
|
|
yuv_info->store = SAMPLE_VEDU_PACKAGE;
|
|
|
|
yuv_info->y_addr = data;
|
|
yuv_info->c_addr = TD_NULL;
|
|
yuv_info->v_addr = TD_NULL;
|
|
yuv_info->y_size = buf_size;
|
|
yuv_info->c_size = 0;
|
|
yuv_info->v_size = 0;
|
|
|
|
yuv_info->sel = SAMPLE_VEDU_ARGB; // ??
|
|
}
|
|
|
|
static td_s32 argb_file_to_memory(sample_yuv_info *file_info, queue_thread_info *thread_info)
|
|
{
|
|
td_u32 i;
|
|
td_u8 *img_ptr = file_info->y_addr;
|
|
|
|
for (i = 0; i < file_info->height; i++, img_ptr += file_info->y_stride) {
|
|
if (fread(img_ptr, file_info->width * 4, 1, thread_info->file_enc) != 1) { /* 4: argb */
|
|
venc_err_printf("read error\n");
|
|
return READ_ERROR;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 sp420_10bit_to_memory(sample_yuv_info *yuv_info, FILE *yuv_file)
|
|
{
|
|
td_u8 *y_ptr = yuv_info->y_addr;
|
|
td_u8 *uv_ptr = yuv_info->c_addr;
|
|
td_u32 y_width = yuv_info->width * YUV_10_BIT;
|
|
td_u32 y_height = yuv_info->height;
|
|
td_u32 uv_width = y_width;
|
|
td_u32 uv_height = y_height / 2; /* 2: sp420 uv height */
|
|
td_u32 i;
|
|
|
|
for (i = 0; i < y_height; i++, y_ptr += yuv_info->y_stride) {
|
|
if (fread(y_ptr, y_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < uv_height; i++, uv_ptr += yuv_info->c_stride) {
|
|
if (fread(uv_ptr, uv_width, 1, yuv_file) != 1) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
|
|
exit:
|
|
printf("error:read yuv\n");
|
|
return READ_ERROR;
|
|
}
|
|
|
|
static td_u32 set_yuv_info(sample_yuv_info *yuv_info, queue_thread_info *thread_info,
|
|
td_u8 *data, td_u32 buf_size)
|
|
{
|
|
td_u32 frame_size = 0;
|
|
|
|
switch (g_yuv_store_type) {
|
|
case YUV_SEMIPLANNER_420_UV:
|
|
case YUV_SEMIPLANNER_420_UV_10BIT:
|
|
set_yuv_info_semi_420_uv(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height +
|
|
yuv_info->c_stride * thread_info->height / 2; /* 2: yuv store formal */
|
|
break;
|
|
case YUV_SEMIPLANNER_420_VU:
|
|
case YUV_SEMIPLANNER_420_VU_10BIT:
|
|
set_yuv_info_semi_420_vu(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height +
|
|
yuv_info->c_stride * thread_info->height / 2; /* 2: yuv store formal */
|
|
break;
|
|
case YUV_PLANNER_420:
|
|
set_yuv_info_planner_420(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height + yuv_info->c_stride * thread_info->height;
|
|
break;
|
|
case YUV_SEMIPLANNER_422_UV:
|
|
set_yuv_info_semi_422_uv(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height + yuv_info->c_stride * thread_info->height;
|
|
break;
|
|
case YUV_SEMIPLANNER_422_VU:
|
|
set_yuv_info_semi_422_vu(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height + yuv_info->c_stride * thread_info->height;
|
|
break;
|
|
|
|
case YUV_PACKAGE_422_YUYV:
|
|
set_yuv_info_package_422_yuyv(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height;
|
|
break;
|
|
case YUV_PACKAGE_422_YVYU:
|
|
set_yuv_info_package_422_yvyu(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height;
|
|
break;
|
|
case YUV_PACKAGE_422_UYVY:
|
|
set_yuv_info_package_422_uyvy(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height;
|
|
break;
|
|
case COLOR_CHANNEL_ARGB_8888:
|
|
set_yuv_info_argb_8888(yuv_info, thread_info, data, buf_size);
|
|
frame_size = yuv_info->y_stride * thread_info->height;
|
|
break;
|
|
}
|
|
|
|
return frame_size;
|
|
}
|
|
|
|
static td_u32 read_buffer_from_yuv_file(queue_thread_info *thread_info, td_u8 *data, td_u32 buf_size)
|
|
{
|
|
sample_yuv_info yuv_info = {};
|
|
|
|
td_u32 frame_size = set_yuv_info(&yuv_info, thread_info, data, buf_size);
|
|
|
|
yuv_info.width = thread_info->width;
|
|
yuv_info.height = thread_info->height;
|
|
|
|
if (g_yuv_store_type == COLOR_CHANNEL_ARGB_8888) {
|
|
if (argb_file_to_memory(&yuv_info, thread_info) != TD_SUCCESS) {
|
|
return 0;
|
|
}
|
|
} else if (g_yuv_store_type == YUV_SEMIPLANNER_420_UV_10BIT || g_yuv_store_type == YUV_SEMIPLANNER_420_VU_10BIT) {
|
|
if (sp420_10bit_to_memory(&yuv_info, thread_info->file_enc) != TD_SUCCESS) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (yuvfile_to_memory(&yuv_info, thread_info->file_enc) != TD_SUCCESS) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return frame_size;
|
|
}
|
|
|
|
td_u32 calc_per_frame_size(td_u32 width, td_u32 height, td_u32 format, float bit_deep)
|
|
{
|
|
td_u32 frame_buf_size = 0;
|
|
if (format == YUV_PLANNER_420) {
|
|
frame_buf_size = (align_up(width, RESOLUTION_ALIGN) +
|
|
align_up(width / 2, RESOLUTION_ALIGN)) * height; /* 2: calculate frame size */
|
|
} else if (format == YUV_SEMIPLANNER_420_UV || format == YUV_SEMIPLANNER_420_VU ||
|
|
format == YUV_SEMIPLANNER_420_UV_10BIT || format == YUV_SEMIPLANNER_420_VU_10BIT) {
|
|
frame_buf_size = align_up(width * bit_deep, RESOLUTION_ALIGN) * height * 3 / 2; /* 3, 2: calculate frame size */
|
|
} else if (format == YUV_PACKAGE_422_YUYV || format == YUV_PACKAGE_422_YVYU || format == YUV_PACKAGE_422_UYVY) {
|
|
frame_buf_size = align_up(width, RESOLUTION_ALIGN) * height * 2; /* 2: calculate frame size */
|
|
} else if (format == YUV_SEMIPLANNER_422_UV || format == YUV_SEMIPLANNER_422_VU) {
|
|
frame_buf_size = align_up(width, RESOLUTION_ALIGN) * height * 2; /* 2: calculate frame size */
|
|
} else if (format == COLOR_CHANNEL_ARGB_8888) {
|
|
frame_buf_size = align_up(width, RESOLUTION_ALIGN) * height * 4; /* 4: argb */
|
|
} else {
|
|
venc_err_printf("not support yuv store type!!!\n");
|
|
}
|
|
|
|
return frame_buf_size;
|
|
}
|
|
|
|
td_s32 alloc_frame_buf(td_u32 chan_id, td_u32 width, td_u32 height)
|
|
{
|
|
uapi_mem_buf buf = {};
|
|
td_u32 i;
|
|
td_u32 per_size;
|
|
td_s32 ret;
|
|
|
|
per_size = calc_per_frame_size(width, height, g_yuv_store_type, g_yuv_bit_deep);
|
|
if (per_size == 0) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
sec_chk_lt_ret(snprintf_s(buf.buf_name, sizeof(buf.buf_name), sizeof(buf.buf_name) - 1,
|
|
"VENC_MMZ_%d", chan_id), TD_FAILURE);
|
|
buf.buf_size = per_size;
|
|
|
|
for (i = 0; i < QFRAME_NUM; i++) {
|
|
ret = uapi_mem_malloc(&buf);
|
|
if (ret == TD_FAILURE) {
|
|
printf("~~~~~~ERROR: uapi_mem_malloc(%d) Failed!! Ret:%d\n", chan_id, ret);
|
|
return TD_FAILURE;
|
|
}
|
|
g_frame_buf[chan_id][i] = buf;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
|
|
td_s32 free_frame_buf(td_u32 chan_id)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
|
|
for (i = 0; i < QFRAME_NUM; i++) {
|
|
ret = uapi_mem_free(&g_frame_buf[chan_id][i]);
|
|
if (ret == TD_FAILURE) {
|
|
printf("~~~~~~ERROR: uapi_mem_free Failed!! Ret:%d\n", ret);
|
|
return TD_FAILURE;
|
|
}
|
|
sec_chk_neq_ret(memset_s(&g_frame_buf[chan_id][i], sizeof(uapi_mem_buf),
|
|
0, sizeof(uapi_mem_buf)), TD_FAILURE);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void set_frame_info_sp420(uapi_video_frame_info *frame_info, td_u32 width, td_u32 height,
|
|
td_mem_handle_t buf_handle)
|
|
{
|
|
frame_info->frame_addr[0].stride_y = align_up((width * g_yuv_bit_deep), RESOLUTION_ALIGN);
|
|
frame_info->frame_addr[0].stride_c = align_up((width * g_yuv_bit_deep), RESOLUTION_ALIGN);
|
|
|
|
frame_info->frame_addr[0].start_addr = buf_handle;
|
|
frame_info->frame_addr[0].y_offset = 0;
|
|
frame_info->frame_addr[0].c_offset = frame_info->frame_addr[0].stride_y * height;
|
|
|
|
frame_info->bit_depth = g_yuv_bit_deep == YUV_10_BIT ?
|
|
UAPI_PIXEL_BIT_DEPTH_10BIT : UAPI_PIXEL_BIT_DEPTH_8BIT;
|
|
|
|
if (g_yuv_store_type == YUV_SEMIPLANNER_420_VU || g_yuv_store_type == YUV_SEMIPLANNER_420_UV_10BIT) {
|
|
frame_info->video_format = UAPI_FORMAT_YUV_SEMIPLANAR_420_VU;
|
|
} else {
|
|
frame_info->video_format = UAPI_FORMAT_YUV_SEMIPLANAR_420_UV;
|
|
}
|
|
}
|
|
|
|
static td_void set_frame_info_planner_420(uapi_video_frame_info *frame_info, td_u32 width, td_u32 height,
|
|
td_mem_handle_t buf_handle)
|
|
{
|
|
frame_info->frame_addr[0].stride_y = align_up(width, 16);
|
|
frame_info->frame_addr[0].stride_c = align_up(width / 2, 16);
|
|
frame_info->frame_addr[0].stride_cr = align_up(width / 2, 16);
|
|
|
|
frame_info->frame_addr[0].start_addr = buf_handle;
|
|
frame_info->frame_addr[0].y_offset = 0;
|
|
frame_info->frame_addr[0].c_offset = frame_info->frame_addr[0].stride_y * height;
|
|
frame_info->frame_addr[0].cr_offset = frame_info->frame_addr[0].c_offset +
|
|
frame_info->frame_addr[0].stride_c * height / 2; /* 2: yuv store type */
|
|
frame_info->video_format = UAPI_FORMAT_YUV_PLANAR_420_UV;
|
|
}
|
|
|
|
static td_void set_frame_info_package_422(uapi_video_frame_info *frame_info, td_u32 width,
|
|
td_mem_handle_t buf_handle)
|
|
{
|
|
frame_info->frame_addr[0].stride_y = align_up(width * 2, 16);
|
|
|
|
frame_info->frame_addr[0].start_addr = buf_handle;
|
|
frame_info->frame_addr[0].y_offset = 0;
|
|
|
|
if (g_yuv_store_type == YUV_PACKAGE_422_YUYV) {
|
|
frame_info->video_format = UAPI_FORMAT_YUV_PACKAGE_YUYV;
|
|
} else if (g_yuv_store_type == YUV_PACKAGE_422_YVYU) {
|
|
frame_info->video_format = UAPI_FORMAT_YUV_PACKAGE_YVYU;
|
|
} else {
|
|
frame_info->video_format = UAPI_FORMAT_YUV_PACKAGE_UYVY;
|
|
}
|
|
}
|
|
|
|
static td_void set_frame_info_argb8888(uapi_video_frame_info *frame_info, td_u32 width,
|
|
td_mem_handle_t buf_handle)
|
|
{
|
|
frame_info->frame_addr[0].stride_y = align_up(width * 4, RESOLUTION_ALIGN); /* 4: argb */
|
|
|
|
frame_info->frame_addr[0].start_addr = buf_handle;
|
|
frame_info->frame_addr[0].y_offset = 0;
|
|
|
|
frame_info->video_format = UAPI_FORMAT_ARGB8888;
|
|
}
|
|
|
|
static td_void set_video_frame_info(uapi_video_frame_info *frame_info, queue_thread_info *thread_info,
|
|
uapi_mem_buf *buf)
|
|
{
|
|
frame_info->display_width = thread_info->width;
|
|
frame_info->display_height = thread_info->height;
|
|
frame_info->decode_width = thread_info->width;
|
|
frame_info->decode_height = thread_info->height;
|
|
frame_info->scan_type = UAPI_VIDEO_SCAN_TYPE_PROGRESSIVE;
|
|
frame_info->field_mode = UAPI_VIDEO_FIELD_ALL;
|
|
frame_info->frame_packing_type = UAPI_FRAME_PACKING_TYPE_2D;
|
|
|
|
if (g_yuv_store_type == YUV_SEMIPLANNER_420_UV || g_yuv_store_type == YUV_SEMIPLANNER_420_VU ||
|
|
g_yuv_store_type == YUV_SEMIPLANNER_420_UV_10BIT || g_yuv_store_type == YUV_SEMIPLANNER_420_VU_10BIT) {
|
|
set_frame_info_sp420(frame_info, thread_info->width, thread_info->height, buf->buf_handle);
|
|
} else if (g_yuv_store_type == YUV_PLANNER_420) {
|
|
set_frame_info_planner_420(frame_info, thread_info->width, thread_info->height, buf->buf_handle);
|
|
} else if (g_yuv_store_type == YUV_PACKAGE_422_YUYV || g_yuv_store_type == YUV_PACKAGE_422_YVYU ||
|
|
g_yuv_store_type == YUV_PACKAGE_422_UYVY) {
|
|
set_frame_info_package_422(frame_info, thread_info->width, buf->buf_handle);
|
|
} else if (g_yuv_store_type == COLOR_CHANNEL_ARGB_8888) {
|
|
set_frame_info_argb8888(frame_info, thread_info->width, buf->buf_handle);
|
|
}
|
|
}
|
|
|
|
static uapi_mem_buf *find_memory_buffer(uapi_video_frame_info *frame_info_release, td_u32 index)
|
|
{
|
|
int i;
|
|
uapi_mem_buf *buf_info = TD_NULL;
|
|
|
|
for (i = 0; i < QFRAME_NUM; i++) {
|
|
if (g_frame_buf[index][i].buf_handle == frame_info_release->frame_addr[0].start_addr) {
|
|
buf_info = &g_frame_buf[index][i];
|
|
break;
|
|
}
|
|
}
|
|
if (i == QFRAME_NUM) {
|
|
printf("Can not find corresponding buffer\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
return buf_info;
|
|
}
|
|
|
|
static td_s64 g_pts = 1;
|
|
|
|
static td_void send_frame_before_start(queue_thread_info *thread_info)
|
|
{
|
|
td_u32 queue_id;
|
|
uapi_video_frame_info frame_info = {0};
|
|
td_u32 read_len;
|
|
uapi_mem_buf *buf_info = TD_NULL;
|
|
td_s32 ret;
|
|
|
|
for (queue_id = 0; queue_id < QFRAME_NUM && thread_info->index < VENC_MAX_CHN; queue_id++) {
|
|
buf_info = &g_frame_buf[thread_info->index][queue_id];
|
|
|
|
read_len = read_buffer_from_yuv_file(thread_info, buf_info->user_viraddr, (td_u32)buf_info->buf_size);
|
|
if (read_len == 0) {
|
|
printf("read vid file error!\n");
|
|
rewind(thread_info->file_enc);
|
|
continue;
|
|
}
|
|
|
|
set_video_frame_info(&frame_info, thread_info, buf_info);
|
|
frame_info.pts = g_pts++;
|
|
|
|
ret = uapi_venc_queue_frame(thread_info->chan_id, &frame_info);
|
|
if (ret != TD_SUCCESS) {
|
|
venc_err_printf("uapi_venc_queue_frame failed!, queue_id = %d\n", queue_id);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef VENC_PROPERTY_TEST
|
|
static td_s32 read_next_frame_to_memory(uapi_mem_buf *buf_info, queue_thread_info *thread_info)
|
|
{
|
|
td_u32 read_len;
|
|
|
|
read_len = read_buffer_from_yuv_file(thread_info, buf_info->user_viraddr, (td_u32)buf_info->buf_size);
|
|
if (read_len == 0) {
|
|
printf("read vid file error!\n");
|
|
rewind(thread_info->file_enc);
|
|
read_len = read_buffer_from_yuv_file(thread_info, buf_info->user_viraddr, (td_u32)buf_info->buf_size);
|
|
if (read_len == 0) {
|
|
printf("ERROR :: miss one Framebuffer!!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
td_void *sample_send_frame_process(td_void *args)
|
|
{
|
|
td_s32 ret;
|
|
uapi_video_frame_info frame_info_release = {0};
|
|
queue_thread_info *thread_info = (queue_thread_info *)args;
|
|
uapi_mem_buf *buf_info = TD_NULL;
|
|
|
|
if (thread_info == TD_NULL) {
|
|
venc_err_printf("thread_info is null!\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
send_frame_before_start(thread_info);
|
|
|
|
while (!g_send_frame_stop) {
|
|
td_u32 retry_cnt = 0;
|
|
|
|
do {
|
|
ret = uapi_venc_dequeue_frame(thread_info->chan_id, &frame_info_release);
|
|
retry_cnt++;
|
|
usleep(5 * 1000); /* 5, 1000: 5ms */
|
|
} while (ret != TD_SUCCESS && retry_cnt < RETRY_CNT && (!g_send_frame_stop));
|
|
|
|
if (retry_cnt >= RETRY_CNT) {
|
|
venc_warn_printf("dequeue timeout, restart send frame\n");
|
|
g_pts = 1;
|
|
send_frame_before_start(thread_info);
|
|
continue;
|
|
}
|
|
|
|
buf_info = find_memory_buffer(&frame_info_release, thread_info->index);
|
|
if (buf_info == TD_NULL) {
|
|
venc_err_printf("find_memory_buffer failed\n");
|
|
continue;
|
|
}
|
|
|
|
#ifndef VENC_PROPERTY_TEST
|
|
ret = read_next_frame_to_memory(buf_info, thread_info);
|
|
if (ret != TD_SUCCESS) {
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
frame_info_release.pts = g_pts++;
|
|
if (g_send_frame_stop != TD_TRUE) {
|
|
ret = uapi_venc_queue_frame(thread_info->chan_id, &frame_info_release);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("QueueFrame err!ret = %x\n", ret);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_s32 venc_create(uapi_venc_attr* venc_attr, td_handle* venc_handle)
|
|
{
|
|
td_s32 ret;
|
|
td_handle chan_id;
|
|
|
|
if (venc_handle == TD_NULL) {
|
|
printf("%s,%d,bad venc_handle !\n", __func__, __LINE__);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = uapi_venc_create(&chan_id, venc_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("UAPI_VENC_CreateChn failed!!\n");
|
|
uapi_venc_deinit();
|
|
return ret;
|
|
}
|
|
|
|
*venc_handle = chan_id;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static td_s32 venc_start(td_handle chan_id)
|
|
{
|
|
td_s32 ret;
|
|
|
|
ret = uapi_venc_start(chan_id);
|
|
if (ret != TD_SUCCESS) {
|
|
uapi_venc_destroy(chan_id);
|
|
uapi_venc_deinit();
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 venc_thread_create(sample_thread_info *input)
|
|
{
|
|
td_u32 i;
|
|
if (input == TD_NULL) {
|
|
venc_err_printf("bad input param\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (i = 0; i < input->real_chn_num; i++) {
|
|
g_save_stream_info[i].chan_id = input->chan_id[i];
|
|
g_save_stream_info[i].file_save = input->file_output[i];
|
|
g_save_stream_info[i].time_out = input->time_out[i];
|
|
|
|
if (g_jpeg_save_type[i] == VCODE_TYPE_JPEG) {
|
|
sec_chk_neq_ret(memcpy_s(g_save_stream_info[i].file_name, sizeof(g_save_stream_info[i].file_name),
|
|
g_output_file_names[i], sizeof(g_output_file_names[i])), TD_FAILURE);
|
|
}
|
|
}
|
|
|
|
g_save_stream_stop = TD_FALSE;
|
|
|
|
for (i = 0; i < input->real_chn_num; i++) {
|
|
if (g_jpeg_save_type[i] == VCODE_TYPE_MJPEG) {
|
|
pthread_create(&g_thread_save_stream[i], TD_NULL, sample_save_stream_process_mjpeg,
|
|
(td_void *)(&g_save_stream_info[i]));
|
|
} else if ((g_jpeg_save_type[i] == VCODE_TYPE_H264) || (g_jpeg_save_type[i] == VCODE_TYPE_H265)) {
|
|
pthread_create(&g_thread_save_stream[i], TD_NULL, sample_save_stream_process,
|
|
(td_void *)(&g_save_stream_info[i]));
|
|
} else if (g_jpeg_save_type[i] == VCODE_TYPE_JPEG) { /* jpeg */
|
|
pthread_create(&g_thread_save_stream[i], TD_NULL, sample_save_stream_process_jpeg,
|
|
(td_void *)(&g_save_stream_info[i]));
|
|
}
|
|
|
|
usleep(2 * 1000); /* 2, 1000: 2ms */
|
|
}
|
|
|
|
for (i = 0; i < input->real_chn_num; i++) {
|
|
g_send_frame_info[i].chan_id = input->chan_id[i];
|
|
g_send_frame_info[i].width = input->pic_width[i];
|
|
g_send_frame_info[i].height = input->pic_height[i];
|
|
g_send_frame_info[i].file_enc = input->file_input[i];
|
|
}
|
|
|
|
g_send_frame_stop = TD_FALSE;
|
|
for (i = 0; i < input->real_chn_num; i++) {
|
|
g_send_frame_info[i].index = i;
|
|
pthread_create(&g_thread_send_frame[i], TD_NULL, sample_send_frame_process, (td_void *)(&g_send_frame_info[i]));
|
|
usleep(2 * 1000); /* 2, 1000: 2ms */
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void venc_thread_stop(td_u32 chn_num)
|
|
{
|
|
td_u32 i;
|
|
if (!g_save_stream_stop) {
|
|
g_save_stream_stop = TD_TRUE;
|
|
for (i = 0; i < chn_num; i++) {
|
|
pthread_join(g_thread_save_stream[i], TD_NULL);
|
|
}
|
|
}
|
|
|
|
if (!g_send_frame_stop) {
|
|
g_send_frame_stop = TD_TRUE;
|
|
for (i = 0; i < chn_num; i++) {
|
|
pthread_join(g_thread_send_frame[i], TD_NULL);
|
|
}
|
|
}
|
|
|
|
printf("Thread stop OK!!\n");
|
|
}
|
|
|
|
|
|
static td_s32 venc_stop(td_handle chan_id)
|
|
{
|
|
return uapi_venc_stop(chan_id);
|
|
}
|
|
|
|
static td_s32 venc_destroy(td_handle chan_id)
|
|
{
|
|
return uapi_venc_destroy(chan_id);
|
|
}
|
|
|
|
static td_void loop_function(td_void)
|
|
{
|
|
while (TD_TRUE) {
|
|
td_char input_cmd;
|
|
|
|
printf("\n************* input 'q' to exit! **************\n");
|
|
fflush(stdin);
|
|
|
|
do {
|
|
if (scanf_s("%c", &input_cmd, 1) < 0) {
|
|
usleep(50000); /* 50000: sleep 50ms */
|
|
continue;
|
|
}
|
|
} while (input_cmd == '\n');
|
|
|
|
if (input_cmd == 'q' || input_cmd == 'Q') {
|
|
break;
|
|
}
|
|
|
|
usleep(50000); /* 50000: sleep 50ms */
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
td_u32 width;
|
|
td_u32 height;
|
|
td_u32 priority;
|
|
uapi_vcodec_type venc_type;
|
|
} channel_info;
|
|
|
|
static td_s32 set_output_file_name(uapi_vcodec_type *venc_type, td_u32 i)
|
|
{
|
|
td_s32 ret;
|
|
td_char file_suffix[FILE_NAME_LENGTH];
|
|
|
|
if (g_jpeg_save_type[i] == VCODE_TYPE_MJPEG) {
|
|
*venc_type = UAPI_VCODEC_TYPE_MJPEG;
|
|
ret = snprintf_s(file_suffix, sizeof(file_suffix), sizeof(file_suffix) - 1, "_chn%02d.mjpeg", i);
|
|
} else if (g_jpeg_save_type[i] == VCODE_TYPE_H264) {
|
|
*venc_type = UAPI_VCODEC_TYPE_H264;
|
|
ret = snprintf_s(file_suffix, sizeof(file_suffix), sizeof(file_suffix) - 1, "_chn%02d.h264", i);
|
|
} else if (g_jpeg_save_type[i] == VCODE_TYPE_JPEG) {
|
|
*venc_type = UAPI_VCODEC_TYPE_MJPEG;
|
|
ret = snprintf_s(file_suffix, sizeof(file_suffix), sizeof(file_suffix) - 1, "_chn%02d", i);
|
|
} else {
|
|
*venc_type = UAPI_VCODEC_TYPE_H265;
|
|
ret = snprintf_s(file_suffix, sizeof(file_suffix), sizeof(file_suffix) - 1, "_chn%02d.h265", i);
|
|
}
|
|
sec_chk_lt_ret(ret, TD_FAILURE);
|
|
|
|
sec_chk_neq_ret(strncat_s(g_output_file_names[i], sizeof(g_output_file_names[i]),
|
|
file_suffix, strlen(file_suffix)), TD_FAILURE);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 config_venc_channel_info(channel_info (*chan_info_ptr)[VENC_MAX_CHN], td_u32 i,
|
|
sample_thread_info *thread_arg)
|
|
{
|
|
channel_info *chan_info = *chan_info_ptr;
|
|
|
|
if (i >= VENC_MAX_CHN) {
|
|
venc_err_printf("i(%d) >= VENC_MAX_CHN", i);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (set_output_file_name(&chan_info[i].venc_type, i) != TD_SUCCESS) {
|
|
venc_err_printf("set_input_output_file_name failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
printf("input the Picture width of channel[%d]:", i);
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &thread_arg->pic_width[i]), TD_FAILURE);
|
|
|
|
printf("input the Picture height of channel[%d]:", i);
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &thread_arg->pic_height[i]), TD_FAILURE);
|
|
|
|
printf("\ninput the Encode width of channel[%d]:", i);
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &chan_info[i].width), TD_FAILURE);
|
|
|
|
printf("input the Encode height of channel[%d]:", i);
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &chan_info[i].height), TD_FAILURE);
|
|
|
|
printf("input the priority of channel[%d]:", i);
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &chan_info[i].priority), TD_FAILURE);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 init_input_file_info(const td_char *input_file_name, FILE **file)
|
|
{
|
|
FILE *file_input = TD_NULL;
|
|
td_char real_path[PATH_MAX] = {};
|
|
|
|
if (realpath(input_file_name, real_path) == TD_NULL) {
|
|
venc_err_printf("get real path %s failed\n", input_file_name);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
file_input = fopen(real_path, "rb");
|
|
if (file_input == TD_NULL) {
|
|
venc_err_printf("ERROR:open file :%s failed!!\n", input_file_name);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
*file = file_input;
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void deinit_file_info(FILE *file)
|
|
{
|
|
if (file != TD_NULL) {
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
static td_s32 init_output_file_info(const td_char *output_file_name, td_u32 type, FILE **file)
|
|
{
|
|
FILE *file_output = TD_NULL;
|
|
td_char file_path[FILE_PATH_LENGTH] = {};
|
|
td_char file_name[FILE_NAME_LENGTH] = {};
|
|
td_char real_path[PATH_MAX] = {};
|
|
td_u32 name_len;
|
|
|
|
if (type != VCODE_TYPE_JPEG) {
|
|
get_file_path(output_file_name, file_path, FILE_PATH_LENGTH, file_name, FILE_NAME_LENGTH);
|
|
|
|
if (realpath(file_path, real_path) == TD_NULL) {
|
|
venc_err_printf("get real path %s failed\n", output_file_name);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
name_len = strlen(file_name) + 1;
|
|
if (strncat_s(real_path, PATH_MAX, file_name, name_len) != EOK) {
|
|
venc_err_printf("get real file name %s failed\n", output_file_name);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
file_output = fopen(real_path, "wb+");
|
|
if (file_output == TD_NULL) {
|
|
venc_err_printf("ERROR:open file :%s failed!!\n", real_path);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
*file = file_output;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
|
|
static td_u32 set_thread_info_user_defined(channel_info (*chan_info_ptr)[VENC_MAX_CHN], sample_thread_info *thread_arg)
|
|
{
|
|
td_u32 chn_num, i;
|
|
td_char input_file_name[VENC_MAX_CHN][FILE_MAX_LENGTH] = {};
|
|
|
|
printf("input the num of VENC channel:");
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &chn_num), 0);
|
|
|
|
if (chn_num > VENC_MAX_CHN) {
|
|
printf("ERROR:: the num of VENC channel is invalid !(should < %d)\n", VENC_MAX_CHN);
|
|
return 0;
|
|
}
|
|
thread_arg->real_chn_num = chn_num;
|
|
|
|
for (i = 0; i < chn_num; i++) {
|
|
printf("input the channel %d encode type (0->h264 1->mjpeg 2->jpeg 3->h265) :", i);
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &g_jpeg_save_type[i]), 0);
|
|
|
|
printf("\ninput the Input Filename of channel[%d]:", i);
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%s", input_file_name[i], sizeof(input_file_name[i])), 0);
|
|
|
|
if (init_input_file_info(input_file_name[i], &thread_arg->file_input[i]) != TD_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
if (config_venc_channel_info(chan_info_ptr, i, thread_arg) != TD_SUCCESS) {
|
|
venc_err_printf("config_venc_channel_info failed");
|
|
return 0;
|
|
}
|
|
|
|
sec_chk_neq_ret(strncpy_s(g_output_file_names[i], sizeof(g_output_file_names[i]),
|
|
input_file_name[i], (strlen(input_file_name[i]) - 4)), 0); /* 4: delete .yuv suffix */
|
|
|
|
if (init_output_file_info(g_output_file_names[i], g_jpeg_save_type[i], &thread_arg->file_output[i])
|
|
!= TD_SUCCESS) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return chn_num;
|
|
}
|
|
|
|
static td_s32 get_encode_type(const td_char *code_type)
|
|
{
|
|
if (!strcmp(code_type, "H264") || !strcmp(code_type, "h264")) {
|
|
g_jpeg_save_type[0] = VCODE_TYPE_H264;
|
|
printf("H264 Type is success!\n");
|
|
} else if (!strcmp(code_type, "H265") || !strcmp(code_type, "h265")) {
|
|
g_jpeg_save_type[0] = VCODE_TYPE_H265;
|
|
printf("H265 Type is success!\n");
|
|
} else if (!strcmp(code_type, "JPG") || !strcmp(code_type, "jpg")) {
|
|
g_jpeg_save_type[0] = VCODE_TYPE_JPEG;
|
|
printf("JPG Type is success!\n");
|
|
} else {
|
|
printf("Please input the VencType H264, H265, or JPG!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_u32 set_thread_info_defualt(channel_info (*chan_info_ptr)[VENC_MAX_CHN], sample_thread_info *thread_arg,
|
|
td_char *argv[])
|
|
{
|
|
channel_info *chan_info = *chan_info_ptr;
|
|
|
|
td_char *file_name = argv[1];
|
|
td_char *width = argv[2]; /* 2: second param */
|
|
td_char *height = argv[3]; /* 3: third param */
|
|
td_u32 file_name_len = strlen(file_name);
|
|
|
|
thread_arg->real_chn_num = 1;
|
|
thread_arg->pic_width[0] = (td_u32)strtol(width, TD_NULL, 0);
|
|
thread_arg->pic_height[0] = (td_u32)strtol(height, TD_NULL, 0);
|
|
chan_info[0].width = (td_u32)strtol(width, TD_NULL, 0);
|
|
chan_info[0].height = (td_u32)strtol(height, TD_NULL, 0);
|
|
chan_info[0].priority = 0;
|
|
|
|
if (get_encode_type(argv[4]) != TD_SUCCESS) { /* 4: code type index */
|
|
return 0;
|
|
}
|
|
|
|
if (file_name_len == 0) {
|
|
return 0;
|
|
}
|
|
|
|
sec_chk_neq_ret(strncpy_s(g_input_file_names[0], sizeof(g_input_file_names[0]),
|
|
file_name, file_name_len), 0);
|
|
sec_chk_neq_ret(strncpy_s(g_output_file_names[0], sizeof(g_output_file_names[0]),
|
|
file_name, file_name_len - 4), 0); /* 4: delete .yuv suffix */
|
|
|
|
if (set_output_file_name(&chan_info[0].venc_type, 0) != TD_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
if (init_input_file_info(g_input_file_names[0], &thread_arg->file_input[0]) != TD_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
if (init_output_file_info(g_output_file_names[0], g_jpeg_save_type[0], &thread_arg->file_output[0]) != TD_SUCCESS) {
|
|
goto err;
|
|
}
|
|
|
|
return thread_arg->real_chn_num;
|
|
|
|
err:
|
|
deinit_file_info(thread_arg->file_input[0]);
|
|
thread_arg->file_input[0] = TD_NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static td_s32 venc_channel_start_encode(channel_info *chan_info, td_u32 chn_num, sample_thread_info *thread_arg)
|
|
{
|
|
td_u32 i;
|
|
uapi_venc_attr venc_attr = {0};
|
|
|
|
for (i = 0; i < chn_num; i++) {
|
|
uapi_venc_get_default_attr(&venc_attr);
|
|
|
|
venc_attr.venc_type = chan_info[i].venc_type;
|
|
venc_attr.max_width = chan_info[i].width;
|
|
venc_attr.max_height = chan_info[i].height;
|
|
venc_attr.stream_buf_size = venc_attr.max_width * venc_attr.max_height * 3 / 2; /* 3, 2: 1.5x resolution */
|
|
|
|
venc_attr.slice_split.enable = TD_FALSE;
|
|
venc_attr.slice_split.mode = UAPI_VENC_SPLIT_MAX;
|
|
venc_attr.slice_split.size = 0;
|
|
|
|
venc_attr.gop_mode = UAPI_VENC_GOP_MODE_NORMALP;
|
|
|
|
venc_attr.config.width = chan_info[i].width;
|
|
venc_attr.config.height = chan_info[i].height;
|
|
venc_attr.config.target_frame_rate = 25 * 1000; /* 25, 1000: 25.000 frame per second */
|
|
venc_attr.config.input_frame_rate = 25 * 1000; /* 25, 1000: 25.000 frame per second */
|
|
venc_attr.config.priority = chan_info[i].priority;
|
|
venc_attr.config.gop = 100; /* 100: gop length */
|
|
venc_attr.config.sp_interval = 0;
|
|
venc_attr.config.input_frame_rate_type = UAPI_VENC_FRAME_RATE_TYPE_USER;
|
|
if (venc_attr.config.width > 2160 || venc_attr.config.height > 2160) { /* 2160: 2K */
|
|
venc_attr.config.target_bitrate = 8 * 1024 * 1024; /* 8, 1024: Recommended bit rate */
|
|
} else if (venc_attr.config.width > 1920 || venc_attr.config.height > 1088) { /* 1920x1088 */
|
|
venc_attr.config.target_bitrate = 5 * 1024 * 1024; /* 5, 1024: Recommended bit rate */
|
|
} else if (venc_attr.config.width > 1280) { /* 1280 resolusion */
|
|
venc_attr.config.target_bitrate = 5 * 1024 * 1024; /* 5, 1024: Recommended bit rate */
|
|
} else if (venc_attr.config.width > 720) { /* 720 resolusion */
|
|
venc_attr.config.target_bitrate = 3 * 1024 * 1024; /* 3, 1024: Recommended bit rate */
|
|
} else if (venc_attr.config.width > 352) { /* 352 resolusion */
|
|
venc_attr.config.target_bitrate = 3 / 2 * 1024 * 1024; /* 3, 2, 1024: Recommended bit rate */
|
|
} else {
|
|
venc_attr.config.target_bitrate = 800 * 1024; /* 800, 1024: Recommended bit rate */
|
|
}
|
|
|
|
if ((g_jpeg_save_type[i] == VCODE_TYPE_JPEG) || (g_jpeg_save_type[i] == VCODE_TYPE_MJPEG)) {
|
|
venc_attr.config.qfactor = 70; /* 70: jpeg default factor */
|
|
}
|
|
|
|
if (venc_create(&venc_attr, &g_venc_chan_id[i]) != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
thread_arg->chan_id[i] = g_venc_chan_id[i];
|
|
thread_arg->time_out[i] = 0;
|
|
if (alloc_frame_buf(i, venc_attr.config.width, venc_attr.config.height) != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
venc_start(g_venc_chan_id[i]);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void venc_channel_stop_encode(sample_thread_info *thread_arg, td_u32 chn_num)
|
|
{
|
|
td_u32 i;
|
|
|
|
for (i = 0; i < chn_num; i++) {
|
|
venc_stop(g_venc_chan_id[i]);
|
|
venc_destroy(g_venc_chan_id[i]);
|
|
if (g_jpeg_save_type[i] != VCODE_TYPE_JPEG) {
|
|
fclose(thread_arg->file_output[i]);
|
|
}
|
|
fclose(thread_arg->file_input[i]);
|
|
|
|
if (free_frame_buf(i) != TD_SUCCESS) {
|
|
venc_err_printf("free_frame_buf(%d) failed\n", i);
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_s32 get_yuv_file_store_type(td_void)
|
|
{
|
|
printf("*********************************************\n");
|
|
printf("please enter input YUV store/sample type\n");
|
|
printf("*********************************************\n");
|
|
printf("0 --> SP420_YCbCr\n");
|
|
printf("1 --> SP420_YCrCb\n");
|
|
printf("2 --> Planner 420\n");
|
|
printf("3 --> Package422_YUYV\n");
|
|
printf("4 --> Package422_YVYU\n");
|
|
printf("5 --> Package422_UYVY\n");
|
|
printf("6 --> ARGB8888\n");
|
|
printf("7 --> SP420_YCbCr_10bit\n");
|
|
|
|
fflush(stdin);
|
|
sec_chk_lt_ret(scanf_s("%d", &g_yuv_store_type), TD_FAILURE);
|
|
fflush(stdin);
|
|
if (g_yuv_store_type >= YUV_SEMIPLANNER_420_VU_10BIT) {
|
|
printf("Wrong option of YUV store/sample type! type(%d) not support!\n", g_yuv_store_type);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (g_yuv_store_type == YUV_SEMIPLANNER_420_UV_10BIT || g_yuv_store_type == YUV_SEMIPLANNER_420_VU_10BIT) {
|
|
g_yuv_bit_deep = YUV_10_BIT;
|
|
} else {
|
|
g_yuv_bit_deep = YUV_8_BIT;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_u32 get_user_input_info(td_s32 argc, td_char *argv[], channel_info (*chan_info_ptr)[VENC_MAX_CHN],
|
|
sample_thread_info *thread_arg)
|
|
{
|
|
td_u32 chn_num = 0;
|
|
|
|
if (argc == 2) { /* 2 parameters */
|
|
if (!strcmp("user-defined", argv[1])) {
|
|
chn_num = set_thread_info_user_defined(chan_info_ptr, thread_arg);
|
|
if (chn_num == 0) {
|
|
venc_err_printf("set_thread_info_user_defined failed\n");
|
|
return chn_num;
|
|
}
|
|
} else {
|
|
goto error_0;
|
|
}
|
|
} else if (argc == 5) { /* 5 parameters */
|
|
chn_num = set_thread_info_defualt(chan_info_ptr, thread_arg, argv);
|
|
if (chn_num == 0) {
|
|
venc_err_printf("set_thread_info_user_defined failed\n");
|
|
return chn_num;
|
|
}
|
|
} else {
|
|
goto error_0;
|
|
}
|
|
|
|
return chn_num;
|
|
|
|
error_0:
|
|
printf("\nUsage1 : %s <filename.yuv> <picture_width> <picture_height> <encode_type>\n", argv[0]);
|
|
printf(" Example: %s 1280x720.yuv 1280 720 H265\n", argv[0]);
|
|
printf("Usage2: %s user-defined\n\n", argv[0]);
|
|
return chn_num;
|
|
}
|
|
|
|
td_s32 main(td_s32 argc, td_char *argv[])
|
|
{
|
|
td_s32 ret;
|
|
td_u32 chn_num;
|
|
sample_thread_info thread_arg = {0};
|
|
channel_info chan_info[VENC_MAX_CHN];
|
|
|
|
chn_num = get_user_input_info(argc, argv, &chan_info, &thread_arg);
|
|
if (chn_num == 0) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (get_yuv_file_store_type() != TD_SUCCESS) {
|
|
venc_err_printf("get_yuv_file_store_type failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
uapi_sys_init();
|
|
|
|
if (uapi_venc_init() != TD_SUCCESS) {
|
|
venc_err_printf("venc init failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
chn_num = chn_num <= VENC_MAX_CHN ? chn_num : VENC_MAX_CHN;
|
|
if (venc_channel_start_encode(chan_info, chn_num, &thread_arg) != TD_SUCCESS) {
|
|
venc_err_printf("set_venc_channel_attr failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (venc_thread_create(&thread_arg) != TD_SUCCESS) {
|
|
venc_err_printf("venc_thread_create failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
sleep(1);
|
|
loop_function();
|
|
|
|
venc_thread_stop(chn_num);
|
|
|
|
venc_channel_stop_encode(&thread_arg, chn_num);
|
|
|
|
ret = uapi_venc_deinit();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_venc_deinit() failed.\n");
|
|
}
|
|
|
|
ret = uapi_sys_deinit();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_sys_deinit() failed.\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|