doubao_chat/apps/demo/demo_DevKitBoard/get_yuv_data.c

284 lines
6.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "system/includes.h"
#include "os/os_api.h"
#include "app_config.h"
#include "get_yuv_data.h"
#include "asm/isc.h"
#include "video_ioctl.h"
#include "device.h"
#include "video.h"
#ifdef CONFIG_VIDEO_ENABLE
#if (defined CONFIG_VIDEO_ENABLE && (__SDRAM_SIZE__ >= (2 * 1024 * 1024)))
#define YUV_TEST 0
#define YUV_BLOCK_SCAN 0
#define YUV_FORMAT_422 0
#if YUV_BLOCK_SCAN
#define YUV_BLOCK_TEST 1 //只获取Y的blok测试
#define YUV_TEST_WIDTH 160 //Y
#define YUV_TEST_HEIGHT 160 //Y
#endif
#if YUV_BLOCK_SCAN
static u8 isc_buf[YUV_DATA_WIDTH * 64 * 3 / 2] SEC(.sram) ALIGNE(32);
#endif
#if YUV_FORMAT_422
static u8 yuv_buf[YUV_DATA_WIDTH * YUV_DATA_HEIGHT * 2] ALIGNE(32);
#else
static u8 yuv_buf[YUV_DATA_WIDTH * YUV_DATA_HEIGHT * 3 / 2] ALIGNE(32);
#endif
#if YUV_BLOCK_TEST
struct yuv_app_info {
volatile u8 *base;
volatile u8 *y;
volatile u8 yuv_used;
volatile u16 w;
volatile u16 h;
volatile u16 line;
};
static struct yuv_app_info yuv_app = {0};
u8 *yuv420_block_buf_get(int *size)
{
if (yuv_app.yuv_used) {
*size = yuv_app.w * yuv_app.h;
return yuv_app.base;
} else {
return NULL;
}
}
void yuv420_block_buf_clean(void)
{
yuv_app.yuv_used = 0;
}
#endif
static get_yuv_cfg __info;
int yuv420_block_scan(void *info)
{
struct yuv_block_info *yuv_info = (struct yuv_block_info *)info;
/*
*算法处理,禁止加延时函数!
*/
if (yuv_info->start) { //帧起始第一个分块
} else {
}
#if YUV_BLOCK_TEST
int i, j, k;
if (!yuv_app.base) {
yuv_app.base = yuv_buf;
yuv_app.y = yuv_app.base;
yuv_app.w = YUV_TEST_WIDTH;
yuv_app.h = YUV_TEST_HEIGHT;
yuv_app.line = 0;
}
if (yuv_app.yuv_used) {
return 0;
}
if (yuv_info->start && yuv_app.line < yuv_app.h) { //根据传入的Y进行裁剪
for (j = 0, k = 0; j < yuv_info->line && k < yuv_info->line; yuv_app.line++) {
for (i = 0; i < yuv_app.w && yuv_app.y < (yuv_app.base + yuv_app.w * yuv_app.h); i++) {
*yuv_app.y++ = *(u8 *)(yuv_info->y + k * yuv_info->width + i * yuv_info->width / yuv_app.w);
}
k = (++j) * yuv_info->height / yuv_app.h;
}
} else if (!yuv_info->start && yuv_app.line >= (yuv_app.h - 8)) { //减8是位流为了防止裁剪不是整除导致行不足
u8 *tmp = yuv_app.y - yuv_app.w;
for (; yuv_app.line < yuv_app.h; yuv_app.line++) {
for (i = 0; i < yuv_app.w && yuv_app.y < (yuv_app.base + yuv_app.w * yuv_app.h); i++) {
*yuv_app.y++ = *(u8 *)(tmp + i);
}
}
yuv_app.y = yuv_app.base;
yuv_app.line = 0;
yuv_app.yuv_used = true;
__asm_csync();
}
#endif
return 0;
}
static void get_yuv_task(void *priv)
{
int err;
struct video_format f = {0};
struct yuv_image yuv = {0};
void *dev;
void (*cb)(u8 * data, u32 len, int width, int height);
/*
*step 1
*/
dev = dev_open(YUV_DATA_SOURCE, NULL);
if (!dev) {
printf("open video err !!!!\n\n");
return;
}
#if 0
/********************YUV内部加外部双BUF,上层处理时间可长一些************************/
/*
*step 2
*/
f.type = VIDEO_BUF_TYPE_VIDEO_OVERLAY;
#if YUV_FORMAT_422
f.pixelformat = VIDEO_PIX_FMT_YUV422;
#else
f.pixelformat = VIDEO_PIX_FMT_YUV420;
#endif
#if YUV_BLOCK_SCAN
f.static_buf = (u8 *)isc_buf;
f.sbuf_size = sizeof(isc_buf);
f.block_done_cb = yuv420_block_scan;
#endif
err = dev_ioctl(dev, VIDIOC_SET_FMT, (u32)&f);
if (err) {
goto error;
}
/*
*step 3
*/
//BUFF配置1:使用外部BUFF,上层处理时间最大为摄像头的帧率时间 - 15ms,GC0308默认驱动处理最大时间35m
#if 1 //YUV分块(行)回调,用不到yuv一帧,则关闭
yuv.addr = (u8 *)yuv_buf;
yuv.size = sizeof(yuv_buf);
#endif
err = dev_ioctl(dev, VIDIOC_SET_OVERLAY, (u32)&yuv);
if (err) {
goto error;
}
#else
/********************YUV支持外部静态BUF,上层处理时间较短************************/
/*
*step 2
*/
f.type = VIDEO_BUF_TYPE_VIDEO_OVERLAY;
f.pixelformat = VIDEO_PIX_FMT_YUV420;
f.static_buf = (u8 *)yuv_buf;
f.sbuf_size = sizeof(yuv_buf);
#if YUV_BLOCK_SCAN
f.block_done_cb = yuv420_block_scan;
#endif
err = dev_ioctl(dev, VIDIOC_SET_FMT, (u32)&f);
if (err) {
goto error;
}
//BUFF配置2:使用内部BUFF,内存节省450K,上层处理时间最大为摄像头的帧结束到帧起始时间,需要看摄像头帧同步信号波形测量,GC0308默认驱动处理最大时间16ms
err = dev_ioctl(dev, VIDIOC_SET_OVERLAY, (u32)0);
if (err) {
goto error;
}
#endif
#if YUV_TEST
FILE *fd = fopen(CONFIG_ROOT_PATH"yuv_1.yuv", "wb+");
int cnt = 0;
#endif
while (1) {
if (thread_kill_req()) {
break;
}
cb = __info.cb;
/*
*step 4
*/
err = dev_ioctl(dev, VIDIOC_GET_OVERLAY, (u32)&yuv);
if (!err) {
//do something in this step
#if YUV_TEST
if (fd) {
cnt++;
fwrite(yuv.addr, 1, yuv.size, fd);
if (cnt > 100) {
fclose(fd);
fd = NULL;
}
printf("write file ok : %d \n", cnt);
}
#else
#if YUV_BLOCK_TEST
int len;
u8 *buf = yuv420_block_buf_get(&len);
if (buf) {
putchar('R');
if (cb) {
cb(buf, len, yuv_app.w, yuv_app.h);
}
yuv420_block_buf_clean();
}
#else
/*
*step 5
*/
dev_ioctl(dev, VIDIOC_CLEAR_OVERLAY, 0);
if (cb) {
cb(yuv.addr, yuv.size, YUV_DATA_WIDTH, YUV_DATA_HEIGHT);
}
#endif
#endif
}
#if YUV_TEST
else if (fd) {
fclose(fd);
fd = NULL;
}
#endif
}
error:
/*
*step 6
*/
dev_close(dev);
__info.init = 0;
}
void get_yuv_init(void (*cb)(u8 *data, u32 len, int width, int height))
{
if (__info.init) {
return;
}
__info.init = 1;
__info.cb = cb;
thread_fork("GET_YUV_TASK", 26, 2048, 0, &__info.pid, get_yuv_task, NULL);
}
void get_yuv_uninit(void)
{
if (!__info.init) {
return;
}
thread_kill(&__info.pid, KILL_WAIT);
__info.cb = NULL;
__info.init = 0;
}
void set_get_yuv_data_cb(void (*cb)(u8 *data, u32 len, int width, int height))
{
__info.cb = cb;
}
#endif
#endif