doubao_chat/apps/wifi_ipc/spi_video.c

888 lines
29 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 "server/video_server.h"
#include "app_config.h"
#include "asm/debug.h"
#include "asm/osd.h"
#include "asm/isc.h"
#include "asm/spi.h"
#include "app_database.h"
#include "storage_device.h"
#include "server/ctp_server.h"
#include "os/os_api.h"
#include "camera.h"
#include "stream_protocol.h"
#include "yuv_soft_scalling.h"
#ifdef CONFIG_NET_ENABLE
#include "net_server.h"
#include "server/net_server.h"
#endif
#ifdef CONFIG_SPI_VIDEO_ENABLE
#if (__SDRAM_SIZE__ < (2*1024*1024))
#error "sdram size no enough , sdram size must >= (2*1024*1024), noto : CONFIG_VIDEO1_ENABLE !!!"
#endif
#define SPI_VIDEO_SPIDEV_NAME "spi2"
#define SPI_VIDEO_YUV_USE_DMA 1 //使用DMA拷贝
#define SPI_VIDEO_REVERSAL 0 //spi镜头翻转 0 90 180 270
#define SPI_VIDEO_XCLK_EN 0 //spi镜头的xclk时钟12M/24M, 1:12M, 0:24M
#define SPI_VIDEO_ONLY_Y 0 //1:只有Y数据
#define SPI_APP_USE_ORIGINAL_SIZE 0 //1:手机APP使用摄像头尺寸不缩放
#define SPI_YUV_ALWAYS_ON 0 //1:YUV一直打开
/////////////////摄像头时钟输出/////////////////////////
#ifdef SPI_VIDEO_XCLK_EN
#ifdef CONFIG_CPU_WL80 //AC79N
#define SPI_VIDEO_XCLK_PORT IO_PORTH_08
#else
#define SPI_VIDEO_XCLK_PORT IO_PORTH_08
#endif
#endif
/*#define SPI_VIDEO_POWERDOWN_IO IO_PORTH_09*/
/////////////////BT656硬件接收/////////////////////////
#define SPI_VIDEO_PCLK_PORT IO_PORTH_04
#define SPI_VIDEO_START_IO_DATA0 IO_PORTH_03
/*#define SPI_VIDEO_PCLK_PORT IO_PORTC_08*/
/*#define SPI_VIDEO_START_IO_DATA0 IO_PORTC_00*/
///////////////////////////////////////////
/**********SPI state ************/
#define SPI_VIDEO_IDEL 0x0
#define SPI_VIDEO_OPEN 0x1
#define SPI_VIDEO_OPENING 0x2
#define SPI_VIDEO_CLOSE 0x3
#define SPI_VIDEO_CLOSEING 0x4
#define SPI_VIDEO_RESEST 0x5
/**********SPI video ************/
#define SPI_LSTART ntohl(0xff000080)
#define SPI_LEND ntohl(0xff00009d)
#define SPI_FSTART ntohl(0xff0000ab)
#define SPI_FEND ntohl(0xff0000b6)
#define SPI_FSTART1 ntohl(0xff0000a9)//spi边缘接收偶尔某些镜头会偏差在头尾
#define SPI_FEND1 ntohl(0xff0000a6)//spi边缘接收偶尔某些镜头会偏差在头尾
#define SPI_FHEAD_SIZE 4
#define SPI_FEND_SIZE 4
#define SPI_LHEAD_SIZE 4
#define SPI_LEND_SIZE 4
#define SPI_CAMERA_W CONFIG_VIDEO1_IMAGE_W //摄像头的分辨率-宽,需要和摄像头驱动设置的输出分辨率寄存器配置一致
#define SPI_CAMERA_H CONFIG_VIDEO1_IMAGE_H //摄像头的分辨率-高,需要和摄像头驱动设置的输出分辨率寄存器配置一致
#if SPI_VIDEO_ONLY_Y
#define SPI_CAMERA_ONLINE_SIZE (SPI_CAMERA_W + SPI_LHEAD_SIZE + SPI_LEND_SIZE)//y
#else
#define SPI_CAMERA_ONLINE_SIZE (SPI_CAMERA_W * 4 / 2 + SPI_LHEAD_SIZE + SPI_LEND_SIZE)//yuv422
#endif
#define SPI_CAMERA_ONEFRAM_SIZE (SPI_CAMERA_ONLINE_SIZE * SPI_CAMERA_H + SPI_FHEAD_SIZE + SPI_FEND_SIZE)
#define SPI_CAMERA_ONLINE_YUV422_SIZE (SPI_CAMERA_W * 4 / 2)
#define SPI_CAMERA_ONFRAM_YUV422_SIZE (SPI_CAMERA_ONLINE_YUV422_SIZE * SPI_CAMERA_H)
#define SPI_CAMERA_ONFRAM_YUV420_SIZE (SPI_CAMERA_W * SPI_CAMERA_H * 3 / 2)
#define SPI_CAMERA_ONFRAM_ONLY_Y_SIZE (SPI_CAMERA_W * SPI_CAMERA_H)
#define SPI_CAMERA_FIRST_DMA_SIZE (SPI_CAMERA_ONEFRAM_SIZE > SPI_MAX_SIZE ? (SPI_MAX_SIZE / SPI_CAMERA_ONLINE_SIZE * SPI_CAMERA_ONLINE_SIZE + SPI_FHEAD_SIZE) : SPI_CAMERA_ONEFRAM_SIZE)
#define SPI_CAMERA_MAX_DMA_CNT (SPI_CAMERA_ONEFRAM_SIZE > SPI_MAX_SIZE ? (SPI_MAX_SIZE / SPI_CAMERA_ONLINE_SIZE * SPI_CAMERA_ONLINE_SIZE) : SPI_MAX_SIZE)
#define SPI_CAMERA_BUFF_FPS 2
#if !CONFIG_SPI_VIDEO_USE_ISC1_RECV
static u8 spi_video_buf[SPI_CAMERA_ONEFRAM_SIZE * SPI_CAMERA_BUFF_FPS] SEC(.sram) ALIGNE(32);
#else
static u8 spi_video_buf[SPI_CAMERA_ONFRAM_YUV420_SIZE * SPI_CAMERA_BUFF_FPS] ALIGNE(32);
#endif
#define SPI_VIDEO_BUFF_SIZE (100*1024)
struct spi_video {
void *spi_hdl;
void *spi_wakeup;
void *camera_hdl;
u8 *fbuf;
u32 fsize;
u8 frame;
u32 out_frame;
u16 width;
u16 height;
struct spi_user su;
u8 reinit;
u8 init;
u8 state;
u8 cpu1_wakeup;
u8 app_state;
u8 yuv_flow;
u32 pid;
struct server *net_video_rec;
u8 *video_buf;
void *net_priv;
void (*yuv_cb)(u8 *buf, u32 size, int width, int height);
#if CONFIG_SPI_VIDEO_USE_ISC1_RECV
u8 *frame_buf;
u32 frame_buf_size;
u32 frame_buf_cnt;
u8 frame_done;
u8 dma_copy_id;
OS_SEM sem;
#endif
} spi_video_info = {0};
void sdfile_save_test(char *buf, int len, char one_file, char close);
int spi_video_task_create(void *priv);
static int spi_camera_close(void);
static struct yuv_block_info spi_blk_info = {0};
static int (*yuv_done_callback)(void *priv, int id, void *blk_info);
static int *yuv_done_callback_priv;
/*int mjpg_yuv_frame_done_callback_set(void *func, void *priv)*/
int yuv_frame_done_callback_set(void *func, void *priv)
{
yuv_done_callback = (int(*)(void *, int, void *))func;
yuv_done_callback_priv = (int *)priv;
__asm_csync();
return 1;
}
static void yuv_frame_done_callback_clear(void)
{
yuv_done_callback = NULL;
yuv_done_callback_priv = NULL;
__asm_csync();
}
#if CONFIG_SPI_VIDEO_USE_ISC1_RECV
int bt656_one_line_framedone_callback(void *priv, int id, void *blk_info)
{
struct yuv_block_info *block_info = (struct yuv_block_info *)blk_info;
char *buf = (char *)block_info->y;
int len = block_info->ylen + block_info->ulen + block_info->vlen;
if (!spi_video_info.frame_done && buf) {
#if SPI_VIDEO_YUV_USE_DMA
spi_video_info.dma_copy_id = dma_copy_async(spi_video_info.frame_buf + spi_video_info.fsize, buf, len);
#else
memcpy(spi_video_info.frame_buf + spi_video_info.fsize, buf, len);
#endif
spi_video_info.frame_done = TRUE;
os_sem_post(&spi_video_info.sem);
return 0;
}
return -EINVAL;
}
#endif
int get_wl80_spec_jpeg_q_val(void)
{
return 7;//spi video Q值返回
}
static int spi_camera_event(void *priv, int argc, int *argv)
{
switch (argv[0]) {
case VIDEO_SERVER_PKG_ERR:
spi_camera_close();
log_e("spi video_server_pkg_err\n");
break;
default:
break;
}
return 0;
}
void spi_video_yuv_cb_reg(void (*cb)(u8 *buf, u32 size, int width, int height))
{
spi_video_info.yuv_cb = cb;
}
int spi_camera_width_get(void)
{
int w;
#if ((SPI_VIDEO_REVERSAL == 0) || ((SPI_VIDEO_REVERSAL == 180)))
w = SPI_CAMERA_W;
#else
w = SPI_CAMERA_H;
#endif
#if SPI_APP_USE_ORIGINAL_SIZE
return w;
#endif
return (w / 32 * 32 * 2) / 32 * 32;//32对齐后,2倍放大
}
int spi_camera_height_get(void)
{
int h;
#if ((SPI_VIDEO_REVERSAL == 0) || ((SPI_VIDEO_REVERSAL == 180)))
h = SPI_CAMERA_H;
#else
h = SPI_CAMERA_W;
#endif
#if SPI_APP_USE_ORIGINAL_SIZE
return h;
#endif
return (h / 16 * 16 * 3 / 2) / 16 * 16;//16对齐后,1.5倍放大
}
int spi_video_wait_done(void)
{
u32 to = 300;
while ((spi_video_info.state == SPI_VIDEO_OPENING || spi_video_info.state == SPI_VIDEO_RESEST) && --to) {
os_time_dly(1);
}
return 0;
}
static int spi_camera_reset(void)
{
int err;
union video_req req = {0};
if (spi_video_info.camera_hdl) {
dev_ioctl(spi_video_info.camera_hdl, CAMERA_SET_SENSOR_RESET, 0);
spi_video_info.state = SPI_VIDEO_OPEN;
} else if (spi_video_info.net_video_rec) {
req.rec.channel = 1;
req.rec.state = 0;//传参
req.rec.priv = (void *)CAMERA_SET_SENSOR_RESET; //镜头复位命令
err = server_request(spi_video_info.net_video_rec, VIDEO_REQ_DEVICE_IOCTL, &req);//请求镜头复位IOCTL
if (err != 0) {
printf("spi_camera_reset err %d \n", err);
return -EINVAL;
}
spi_video_info.state = SPI_VIDEO_OPEN;
}
return 0;
}
static int net_stream_open(void *net_priv)
{
int err = 0;
#ifdef CONFIG_NET_ENABLE
union video_req req = {0};
struct video_text_osd text_osd = {0};
struct video_graph_osd graph_osd;
u16 max_one_line_strnum;
if (!spi_video_info.video_buf) {
spi_video_info.video_buf = malloc(SPI_VIDEO_BUFF_SIZE);
if (!spi_video_info.video_buf) {
err = -EINVAL;
goto error;
}
}
if (spi_video_info.net_video_rec) {
printf("net_stream_open is open \n");
return 0;
} else {
spi_video_info.net_video_rec = server_open("video_server", "video1.0");
if (!spi_video_info.net_video_rec) {
err = -EINVAL;
goto error;
}
server_register_event_handler(spi_video_info.net_video_rec, (void *)0, spi_camera_event);
}
req.rec.bfmode = VIDEO_PPBUF_MODE;
req.rec.wl80_spec_mode = VIDEO_WL80_SPEC_DOUBLE_REC_MODE;
req.rec.picture_mode = 0;//非绘本模式
req.rec.isc_sbuf = NULL;
req.rec.sbuf_size = 0;
req.rec.block_done_cb = NULL;
req.rec.camera_type = VIDEO_CAMERA_NORMAL;
req.rec.channel = 1;
req.rec.width = spi_camera_width_get();
req.rec.height = spi_camera_height_get();
req.rec.state = VIDEO_STATE_START;
req.rec.fpath = CONFIG_REC_PATH_0;
req.rec.format = NET_VIDEO_FMT_AVI;
req.rec.fname = "vid_***.avi";
req.rec.quality = VIDEO_MID_Q;
req.rec.fps = 0;
req.rec.real_fps = 15;
req.rec.net_par.net_audrt_onoff = 0;
req.rec.net_par.net_vidrt_onoff = 1;
req.rec.audio.sample_rate = 0;
req.rec.audio.channel = 1;
req.rec.audio.channel_bit_map = 0;
req.rec.audio.volume = 0;
req.rec.audio.buf = NULL;
req.rec.audio.buf_len = 0;
req.rec.pkg_mute.aud_mute = !db_select("mic");
/*
*码率,I帧和P帧比例,必须是偶数(当录MOV的时候才有效),
*roio_xy :值表示宏块坐标, [6:0]左边x坐标 ,[14:8]右边x坐标,[22:16]上边y坐标,[30:24]下边y坐标,写0表示1个宏块有效
* roio_ratio : 区域比例系数
*/
req.rec.abr_kbps = 0;
req.rec.IP_interval = 0;
/*
*慢动作倍数(与延时摄影互斥,无音频); 延时录像的间隔ms(与慢动作互斥,无音频)
*/
req.rec.slow_motion = 0;
req.rec.tlp_time = 0;//db_select("gap");
req.rec.buf = spi_video_info.video_buf;
req.rec.buf_len = SPI_VIDEO_BUFF_SIZE;
if (net_priv) {
struct sockaddr_in *addr = ctp_srv_get_cli_addr(net_priv);
if (!addr) {
addr = cdp_srv_get_cli_addr(net_priv);
}
#if (defined CONFIG_NET_UDP_ENABLE)
sprintf(req.rec.net_par.netpath, "udp://%s:%d"
, inet_ntoa(addr->sin_addr.s_addr)
, _BEHIND_PORT);
#elif (defined CONFIG_NET_TCP_ENABLE)
sprintf(req.rec.net_par.netpath, "tcp://%s:%d"
, inet_ntoa(addr->sin_addr.s_addr)
, _BEHIND_PORT);
#elif (defined CONFIG_USR_VIDEO_ENABLE)
sprintf(req.rec.net_par.netpath, "usr://%s", CONFIG_USR_PATH);
#endif
} else {
#if (defined CONFIG_USR_VIDEO_ENABLE)
sprintf(req.rec.net_par.netpath, "usr://%s", CONFIG_USR_PATH);
#endif
}
err = server_request(spi_video_info.net_video_rec, VIDEO_REQ_REC, &req);
if (err != 0) {
printf("start rec err = %d\n", err);
err = -EINVAL;
goto error;
}
printf(">>>>>>spi video width=%d height=%d\n", req.rec.width, req.rec.height);
req.rec.priv = (void *)yuv_frame_done_callback_set;
server_request(spi_video_info.net_video_rec, VIDEO_REQ_SET_ANOTHER_YUV_CALLBACK, &req);
#else
printf("\nerr spi video open !!!\n\n");
#endif
return err;
error:
spi_video_info.state = SPI_VIDEO_CLOSE;
if (spi_video_info.net_video_rec) {
server_close(spi_video_info.net_video_rec);
spi_video_info.net_video_rec = NULL;
}
return err;
}
static int net_stream_close(void)
{
int err = 0;
u8 state = spi_video_info.state;
yuv_frame_done_callback_clear();
if (spi_video_info.net_video_rec) {
union video_req req = {0};
req.rec.channel = 1;
req.rec.state = VIDEO_STATE_STOP;
err = server_request(spi_video_info.net_video_rec, VIDEO_REQ_REC, &req);
if (err != 0) {
printf("spi video stop rec err %d\n", err);
spi_video_info.state = state;
return -EINVAL;
}
server_close(spi_video_info.net_video_rec);
spi_video_info.net_video_rec = NULL;
}
return err;
}
static int spi_camera_open(void *net_priv)
{
int err = 0;
if (spi_video_info.state == SPI_VIDEO_OPEN || spi_video_info.state == SPI_VIDEO_OPENING) {
puts("spi video is open \n");
return 0;
}
/*------SPI摄像头的CLK,OUP_CH2 24M-----*/
#ifdef SPI_VIDEO_POWERDOWN_IO
gpio_direction_output(SPI_VIDEO_POWERDOWN_IO, 0);
#endif
#ifdef SPI_VIDEO_XCLK_EN
#if SPI_VIDEO_XCLK_EN
gpio_set_output_clk(SPI_VIDEO_XCLK_PORT, 12);
#else
gpio_output_channle(SPI_VIDEO_XCLK_PORT, CH3_PLL_24M);
#endif
#endif
if (spi_video_info.state == SPI_VIDEO_RESEST) {
printf("--->SPI_VIDEO_RESEST\n");
spi_video_info.state = SPI_VIDEO_OPENING;
return spi_camera_reset();
}
spi_video_info.state = SPI_VIDEO_OPENING;
if (!net_priv) {
spi_video_info.camera_hdl = dev_open("video1.0", NULL);
if (!spi_video_info.camera_hdl) {
printf("camera open err\n");
err = -EINVAL;
goto error;
}
} else {
err = net_stream_open(net_priv);
}
spi_video_info.state = SPI_VIDEO_OPEN;
printf("camera open ok\n");
return 0;
error:
spi_video_info.state = SPI_VIDEO_CLOSE;
if (spi_video_info.net_video_rec) {
server_close(spi_video_info.net_video_rec);
spi_video_info.net_video_rec = NULL;
}
return err;
}
static int spi_camera_close(void)
{
int err = 0;
u8 state;
if (!spi_video_info.init) {
printf("spi_video no init \n");
return -EINVAL;
}
if (spi_video_info.state == SPI_VIDEO_CLOSE || spi_video_info.state == SPI_VIDEO_CLOSEING) {
puts("spi video is close \n");
return 0;
}
state = spi_video_info.state;
spi_video_info.state = SPI_VIDEO_CLOSEING;
#ifdef SPI_VIDEO_POWERDOWN_IO
gpio_direction_output(SPI_VIDEO_POWERDOWN_IO, 1);
#endif
#ifdef SPI_VIDEO_XCLK_EN
#if SPI_VIDEO_XCLK_EN
gpio_clear_output_clk(SPI_VIDEO_XCLK_PORT, 12);
#else
gpio_clear_output_channle(SPI_VIDEO_XCLK_PORT, CH3_PLL_24M);
#endif
#endif
if (spi_video_info.camera_hdl) {
dev_close(spi_video_info.camera_hdl);
spi_video_info.camera_hdl = NULL;
}
err = net_stream_close();
spi_video_info.state = SPI_VIDEO_CLOSE;
return err;
}
static void spi_video_task(void *priv)
{
int ret;
u8 *read_buf;
u8 *read_addr;
int max = 0;
int wlen = 0;
int yaddr, uaddr, vaddr;
int offset, yoffset, uoffset, voffset;
int sline_cnt;
int online_data_size;
int sample_wcnt;
int sample_hcnt;
int *head;
int *end;
int msg[4];
reinit:
spi_video_info.net_priv = priv;
spi_video_info.reinit = FALSE;
spi_video_info.frame = SPI_CAMERA_BUFF_FPS;
spi_video_info.width = SPI_CAMERA_W;
spi_video_info.height = SPI_CAMERA_H;
#if !CONFIG_SPI_VIDEO_USE_ISC1_RECV
#if SPI_VIDEO_ONLY_Y
spi_video_info.fsize = SPI_CAMERA_ONFRAM_ONLY_Y_SIZE;
#else
spi_video_info.fsize = SPI_CAMERA_ONFRAM_YUV422_SIZE;
#endif
spi_video_info.su.first_dma_size = SPI_CAMERA_FIRST_DMA_SIZE;
spi_video_info.su.dma_max_cnt = SPI_CAMERA_MAX_DMA_CNT;
spi_video_info.su.block_size = SPI_CAMERA_ONEFRAM_SIZE;
spi_video_info.su.buf_size = spi_video_info.su.block_size * spi_video_info.frame;
if (!spi_video_info.su.buf) {
spi_video_info.su.buf = spi_video_buf;//malloc(spi_video_info.su.buf_size);
if (!spi_video_info.su.buf) {
printf("no mem spi video \n");
goto exit;
}
}
if (!spi_video_info.fbuf) {
spi_video_info.fbuf = malloc(spi_video_info.fsize);
if (!spi_video_info.fbuf) {
printf("no mem spi video frame\n");
goto exit;
}
}
spi_video_info.spi_hdl = dev_open(SPI_VIDEO_SPIDEV_NAME, NULL);
if (!spi_video_info.spi_hdl) {
printf("spi open err \n");
goto exit;
}
#else
spi_video_info.frame_done = FALSE;
spi_video_info.frame_buf_cnt = 0;
spi_video_info.fsize = SPI_CAMERA_ONFRAM_YUV420_SIZE;
spi_video_info.frame_buf_size = SPI_CAMERA_ONFRAM_YUV420_SIZE * SPI_CAMERA_BUFF_FPS;
if (!spi_video_info.frame_buf) {
spi_video_info.frame_buf = spi_video_buf;//malloc(spi_video_info.frame_buf_size);
if (!spi_video_info.frame_buf) {
printf("no mem spi video \n");
goto exit;
}
}
if (!spi_video_info.fbuf) {
spi_video_info.fbuf = malloc(spi_video_info.fsize);
if (!spi_video_info.fbuf) {
printf("no mem spi video frame\n");
goto exit;
}
}
os_sem_set(&spi_video_info.sem, 0);
bt656_one_line_init((u32)spi_video_info.frame_buf,
spi_video_info.width * spi_video_info.height * 3 / 2,
spi_video_info.width,
spi_video_info.height,
SEN_IN_FORMAT_YUYV);
bt656_one_line_framedone_reg((int *)bt656_one_line_framedone_callback, NULL);
#endif
u8 cnt = 5;
redo:
if (spi_camera_open(spi_video_info.net_priv)) {
if (--cnt > 0) {
goto redo;
}
goto exit;
}
#if !CONFIG_SPI_VIDEO_USE_ISC1_RECV
dev_ioctl(spi_video_info.spi_hdl, IOCTL_SPI_SET_IRQ_CPU_ID, (u32)1);
dev_ioctl(spi_video_info.spi_hdl, IOCTL_SPI_SET_USER_INFO, (u32)&spi_video_info.su);//最后一步再设置
#else
//在1/2/4bit情况下,SEN_MBUS_PCKL_NO_FILTER和SEN_MBUS_PCLK_SAMPLE_RISING、SEN_MBUS_PCLK_SAMPLE_FALLING相关
bt656_one_line_io_init(SPI_VIDEO_PCLK_PORT,
SEN_MBUS_PCLK_SAMPLE_FALLING,
0,
SPI_VIDEO_START_IO_DATA0,
CONFIG_SPI_ONE_LINE_ENABLE == 0 ? 2 : 1);//单双线
#if (CONFIG_SPI_ONE_LINE_ENABLE == 0)
/* 使能硬件接收,在2/4bit下,最后一步在配置MSB正反向和移位(因为camera_device_open有可能会对MSB正反向和移位进行重置)*/
bt656_one_line_databits_config(SEN_MBUS_DATA_WIDTH_2B, 0, 6);//按照移位来配置对应输入IO
/*bt656_one_line_databits_config(SEN_MBUS_DATA_WIDTH_2B, 1, 6);//按照移位来配置对应输入IO*/
/*bt656_one_line_databits_config(SEN_MBUS_DATA_WIDTH_2B, 1, 1);//按照移位来配置对应输入IO*/
#endif
bt656_one_line_en(1);//最后一步再打开
#endif
spi_video_info.init = TRUE;
spi_video_info.out_frame = 0;
while (1) {
os_taskq_accept(ARRAY_SIZE(msg), msg);
#if !CONFIG_SPI_VIDEO_USE_ISC1_RECV
ret = dev_ioctl(spi_video_info.spi_hdl, IOCTL_SPI_READ_DATA, (u32)&read_addr);
if (thread_kill_req()) {
break;
}
if (ret > 0) {
head = (int *)read_addr; //校验
end = (int *)&read_addr[ret - 4]; //校验
if ((*head == SPI_FSTART || *head == SPI_FSTART1) && (*end == SPI_FEND || *end == SPI_FEND1)) {
spi_video_info.out_frame++;
if (spi_video_info.out_frame <= 4) {//打开镜头后的前几帧出现光强变化:由黑变亮,在接收数据出错重新打开会使得APP出现闪光
dev_ioctl(spi_video_info.spi_hdl, IOCTL_SPI_FREE_DATA, 0);
continue;
}
wlen = 0;
offset = 0;
sline_cnt = 0;
read_buf = read_addr;
read_buf += SPI_FHEAD_SIZE;//偏移头
online_data_size = SPI_CAMERA_ONLINE_SIZE - SPI_LHEAD_SIZE - SPI_LEND_SIZE;
while (wlen < spi_video_info.fsize && offset < ret) {
head = (int *)read_buf;
if (*head == SPI_LSTART) {
sline_cnt++;
memcpy((int)read_addr + wlen, (int)head + SPI_LHEAD_SIZE, online_data_size);
wlen += online_data_size;
read_buf += SPI_CAMERA_ONLINE_SIZE;
offset += SPI_CAMERA_ONLINE_SIZE;
continue;
} else if (*head == SPI_FEND) {
break;
}
read_buf += SPI_LHEAD_SIZE;
offset += SPI_LHEAD_SIZE;
if (offset >= ret) {
break;
}
}
//printf("--->wlen=%d, %d, %d ",wlen,spi_video_info.fsize,sline_cnt,spi_video_info.height);
if (wlen == spi_video_info.fsize && sline_cnt == spi_video_info.height) {
int out_w = spi_video_info.width;
int out_h = spi_video_info.height;
int src_w = spi_video_info.width;
int src_h = spi_video_info.height;
memcpy(spi_video_info.fbuf, read_addr, wlen);
putchar('R');
#if !SPI_VIDEO_ONLY_Y
read_buf = read_addr;
wlen = YUYV422ToYUV422p(spi_video_info.fbuf, read_buf, src_w, src_h);
wlen = YUV422pToYUV420p(read_buf, spi_video_info.fbuf, src_w, src_h);
#if SPI_VIDEO_REVERSAL
wlen = YUV420p_REVERSAL(spi_video_info.fbuf, read_buf, src_w, src_h, &out_w, &out_h, SPI_VIDEO_REVERSAL);
#endif
if (!wlen) {
goto free_data;
}
//使用地址:read_buf , 使用长度:wlen
if (spi_video_info.yuv_cb) {
spi_video_info.yuv_cb(read_buf, wlen, out_w, out_h);
}
src_w = out_w;
src_h = out_h;
if (yuv_done_callback && spi_video_info.app_state) {
/*************宽32对齐,高16对齐,对齐后进行YUV提取****************/
YUV420p_ALIGN(read_buf, src_w, src_h, &out_w, &out_h, 32, 16);
spi_blk_info.y = (u8 *)read_buf;
spi_blk_info.u = spi_blk_info.y + out_w * out_h;
spi_blk_info.v = spi_blk_info.u + out_w * out_h / 4;
spi_blk_info.width = out_w;
spi_blk_info.height = out_h;
yuv_done_callback((void *)yuv_done_callback_priv, 1, (void *)&spi_blk_info);
} else {
/*
static u32 cnt = 0;
cnt++;
sdfile_save_test(read_buf, src_w * src_h * 3 / 2, 1, cnt % 100 == 0);
*/
}
#endif
}
free_data:
dev_ioctl(spi_video_info.spi_hdl, IOCTL_SPI_FREE_DATA, 0);
} else {
printf("---->SPI_FSTART = 0x%x , 0x%x \n", SPI_FSTART, SPI_FEND);
printf(" SPI_FSTART = 0x%x , 0x%x \n", SPI_FSTART1, SPI_FEND1);
printf("---->err head = 0x%x , 0x%x \n", *head, *end);
printf("recv data err , reinit spi camera !!!\n");
dev_ioctl(spi_video_info.spi_hdl, IOCTL_SPI_FREE_DATA, 0);
spi_video_info.reinit = TRUE;//需要重新打开摄像头
spi_video_info.state = SPI_VIDEO_RESEST;
break;
}
}
#else
ret = os_sem_pend(&spi_video_info.sem, 100);
if (thread_kill_req()) {
break;
}
if (!ret) {
if (spi_video_info.frame_done) {
u8 *yuv_buf = spi_video_info.frame_buf + spi_video_info.fsize;
int out_w = spi_video_info.width;
int out_h = spi_video_info.height;
int src_w = spi_video_info.width;
int src_h = spi_video_info.height;
spi_video_info.frame_buf_cnt++;
#if SPI_VIDEO_YUV_USE_DMA
dma_copy_async_wait(spi_video_info.dma_copy_id);
#endif
read_buf = spi_video_info.fbuf;
wlen = YUV420p_REVERSAL(yuv_buf, read_buf, src_w, src_h, &out_w, &out_h, SPI_VIDEO_REVERSAL);
if (!wlen) {
goto free_data;
}
//使用地址:read_buf , 使用长度:wlen
if (spi_video_info.yuv_cb) {
spi_video_info.yuv_cb(read_buf, wlen, out_w, out_h);
}
src_w = out_w;
src_h = out_h;
/*************宽32对齐,高16对齐,对齐后进行YUV提取****************/
if (yuv_done_callback) {
YUV420p_ALIGN(read_buf, src_w, src_h, &out_w, &out_h, 32, 16);
spi_blk_info.y = (u8 *)read_buf;
spi_blk_info.u = spi_blk_info.y + out_w * out_h;
spi_blk_info.v = spi_blk_info.u + out_w * out_h / 4;
spi_blk_info.width = out_w;
spi_blk_info.height = out_h;
yuv_done_callback((void *)yuv_done_callback_priv, 1, (void *)&spi_blk_info);
} else {
putchar('R');
/*
static u32 cnt = 0;
cnt++;
sdfile_save_test(read_buf, src_w * src_h * 3 / 2, 1, cnt % 100 == 0);
*/
}
free_data:
spi_video_info.frame_done = FALSE;
}
} else {
printf("yuv recv timeout \n");
}
#endif
}
exit:
if (spi_video_info.spi_hdl) {
dev_close(spi_video_info.spi_hdl);
spi_video_info.spi_hdl = NULL;
}
if (spi_video_info.reinit) {
goto reinit;
}
#if CONFIG_SPI_VIDEO_USE_ISC1_RECV
bt656_one_line_exit();
#endif
if (spi_video_info.net_video_rec) {
spi_camera_close();
spi_video_info.net_video_rec = NULL;
}
if (spi_video_info.su.buf) {
/*free(spi_video_info.su.buf);*/
spi_video_info.su.buf = NULL;
}
if (spi_video_info.fbuf) {
free(spi_video_info.fbuf);
spi_video_info.fbuf = NULL;
}
spi_video_info.init = FALSE;
printf("\n\n spi_video_task exit \n\n");
}
int spi_video_task_create(void *priv)
{
int to = 50;
int err;
#if SPI_YUV_ALWAYS_ON
if (spi_video_info.init) {
printf("spi_video already open \n");
if (priv) {
return net_stream_open(priv);
}
return 0;
}
#endif
spi_video_wait_done();
err = spi_camera_close();
if (!err) {
thread_kill(&spi_video_info.pid, 0);//关闭再重新打开
}
if (priv) {
spi_video_info.app_state = TRUE;
printf("---> app open \n");
} else {
spi_video_info.yuv_flow = TRUE;
printf("---> yuv_flow open \n");
}
#if CPU_CORE_NUM == 1
if (!spi_video_info.cpu1_wakeup) {
EnableOtherCpu();
spi_video_info.cpu1_wakeup = true;
}
#endif
#if CONFIG_SPI_VIDEO_USE_ISC1_RECV
if (!os_sem_valid(&spi_video_info.sem)) {
os_sem_create(&spi_video_info.sem, 0);
}
#endif
thread_fork("spi_video_task", 10, 512, 64, &spi_video_info.pid, spi_video_task, priv);
while (!spi_video_info.init && to--) {
os_time_dly(1);
}
if (spi_video_info.init) {
return 0;
}
return -EINVAL;
}
int spi_video_task_init(void)
{
printf("---> spi_video_task_init\n");
spi_video_task_create(NULL);
return 0;
}
int spi_video_task_kill(void *priv)
{
#if SPI_YUV_ALWAYS_ON
if (priv) {
return net_stream_close();
}
#endif
spi_video_wait_done();
#if CONFIG_SPI_VIDEO_USE_ISC1_RECV
if (os_sem_valid(&spi_video_info.sem)) {
os_sem_post(&spi_video_info.sem);
}
#endif
if (priv) {
spi_video_info.app_state = FALSE;
if (spi_video_info.yuv_flow) {
thread_kill(&spi_video_info.pid, 0);//关闭再重新打开
spi_video_task_create(NULL);
}
printf("---> app close \n");
} else {
spi_video_info.yuv_flow = FALSE;
if (spi_video_info.app_state) {
thread_kill(&spi_video_info.pid, 0);//关闭再重新打开
spi_video_task_create(spi_video_info.net_priv);
}
printf("---> yuv_flow close \n");
}
if (spi_video_info.init && !spi_video_info.app_state && !spi_video_info.yuv_flow) {
printf("---> spi video task kill \n");
thread_kill(&spi_video_info.pid, 0);
#if CONFIG_SPI_VIDEO_USE_ISC1_RECV
if (os_sem_valid(&spi_video_info.sem)) {
os_sem_del(&spi_video_info.sem, 0);
}
#endif
}
return 0;
}
#endif
void sdfile_save_test(char *buf, int len, char one_file, char close)
{
static FILE *one_fd = NULL;
if (one_file) {
if (!one_fd) {
/*one_fd = fopen(CONFIG_ROOT_PATH"YUV/test/jpg_***.jpg", "w+");*/
one_fd = fopen(CONFIG_ROOT_PATH"YUV/test/yuv_***.yuv", "w+");
}
if (one_fd && len) {
fwrite(buf, 1, len, one_fd);
}
} else if (!one_file) {
/*FILE *fd = fopen(CONFIG_ROOT_PATH"YUV/test/jpg_***.jpg", "w+");*/
FILE *fd = fopen(CONFIG_ROOT_PATH"YUV/test/yuv_***.yuv", "w+");
if (fd) {
if (len) {
fwrite(buf, 1, len, fd);
}
fclose(fd);
printf("---> writing ok size = %d\n", len);
}
}
if (close && one_fd) {
fclose(one_fd);
one_fd = NULL;
printf("---> close file \n\n");
}
}