888 lines
29 KiB
C
888 lines
29 KiB
C
|
||
#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");
|
||
}
|
||
}
|
||
|