V4L2从摄像头取数据

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <pthread.h>

#include <linux/fb.h>

#include <linux/videodev.h>

#include "hi_unf_common.h"

#include "hi_unf_avplay.h"

#include "hi_unf_sound.h"

#include "hi_unf_disp.h"

#include "hi_unf_vo.h"

#include "hi_unf_vi.h"

#include "hi_unf_venc.h"

#include "hi_unf_demux.h"

#include "hi_unf_hdmi.h"

#include "hi_unf_ecs.h"

#include "hi_adp.h"

#include "hi_adp_audio.h"

#include "hi_adp_hdmi.h"

//#include "hi_adp_boardcfg.h"

//#include "hi_adp_mpi.h"

//#include "hi_adp_tuner.h"

#include "porting_camera.h"

#include "porting_debug.h"

#include "porting_vout.h"

/******************************************************************

********************** USB CAM ************************************

******************************************************************/

#define CAM_FPS  30

#define SAMPLE_USB_CAM_BUFFER_NUM 6

#define SAMPLE_VI_USB_CAM_WIDTH  640

#define SAMPLE_VI_USB_CAM_HEIGHT 480

typedef struct UsbCamBuffer

{

void *pAddr;

UINT32_T  length;

}USB_CAM_Buffer_S;

typedef struct hiUSB_CAM_THREAD_ARG_S

{

UINT32_T   hVi;

UINT32_T      u32USBCamFmt;

int         UsbCamFd;

}USB_CAM_THREAD_ARG_S;

typedef struct hiVENC_THREAD_ARG_S

{

UINT32_T   hVenc;

UINT32_T   hAvplayForVdec;

FILE       *pFileToSave;

}VENC_THREAD_ARG_S;

USB_CAM_Buffer_S UsbCamBuff[SAMPLE_USB_CAM_BUFFER_NUM];

USB_CAM_THREAD_ARG_S g_stUSBCamArgs;

static char *UsbCamDev = "/dev/video0";

static char *TmpCamDev = "/dev/video1";

static pthread_t g_thCAMVi = 0;//VI线程标志符

static pthread_t g_thCAMVenc = 0;;//Venc线程标志符

static HI_BOOL g_whCAMVi, g_whCAMVenc;//控制线程函数的循环

static HI_HANDLE g_hCAMVi;//VI句柄

static HI_HANDLE g_hCAMVenc;//编码器句柄

static HI_BOOL CleanBuf = HI_FALSE;//请buffer标志

static HI_BOOL g_ReadStop = HI_FALSE, writing0=HI_FALSE, writing1=HI_FALSE;

static HI_HANDLE g_Winhdl=0;

//循环buffer用

#define LOOP_BUFF_SIZE (1024*128)  //128KB

#define min(x,y) ({ \

typeof(x) _x = (x); \

typeof(y) _y = (y); \

(void) (&_x == &_y);   \

_x < _y ? _x : _y; })

static struct loop_bufCAM {

pthread_mutex_t mutex;

unsigned char buffer[LOOP_BUFF_SIZE]; //数组,不用通过free()释放

unsigned int in;

unsigned int out;

}CAM_buf,*PCAM_buf=&CAM_buf;

/*local function*/

static void* VencRoutine(void* args);

int init_loop_bufCAM(struct loop_bufCAM *buf)

{

memset(buf->buffer, 0, LOOP_BUFF_SIZE);

buf->in = buf->out = 0;

pthread_mutex_init(&buf->mutex,NULL);

return 0;

}

UINT32_T UsbCamDeinit(USB_CAM_THREAD_ARG_S *pArgs);

HI_HANDLE camera_attach_window(HI_HANDLE vihandle);

void camera_detach_window(HI_HANDLE vihandle);

void porting_camera_set_location_by_rect(void *arg);

unsigned int put_loop_bufCAM(struct loop_bufCAM *buf, unsigned char *buffer, unsigned int len)

{

unsigned int l;

len = min(len, LOOP_BUFF_SIZE - buf->in + buf->out);

/* first put the data starting from buf->in to buffer end */

l = min(len, LOOP_BUFF_SIZE - (buf->in & (LOOP_BUFF_SIZE - 1)));

memcpy(buf->buffer + (buf->in & (LOOP_BUFF_SIZE - 1)), buffer, l);

/* then put the rest (if any) at the beginning of the buffer */

memcpy(buf->buffer, buffer + l, len - l);

buf->in += len;

// printf("len=%d, buf->in = %d, buf->out=%d \n",len, buf->in, buf->out);

if(buf->in == LOOP_BUFF_SIZE)

{

buf->in = 0;

}

return len;

}

unsigned int get_loop_bufCAM(struct loop_bufCAM *buf, unsigned char *buffer, unsigned int len)

{

unsigned int l;

len = min(len, buf->in - buf->out);

// printf("len=%d,buf->in=%d,buf->out=%d\n",len,buf->in,buf->out);

/* first get the data from buf->out until the end of the buffer */

l = min(len, LOOP_BUFF_SIZE - (buf->out & (LOOP_BUFF_SIZE - 1)));

memcpy(buffer, buf->buffer + (buf->out & (LOOP_BUFF_SIZE - 1)), l);

/* then get the rest (if any) from the beginning of the buffer */

memcpy(buffer + l, buf->buffer, len - l);

buf->out += len;

if (buf->out == buf->in )

buf->out=buf->in = 0;

return len;

}

void lock_bufCAM(struct loop_bufCAM *buf)

{

pthread_mutex_lock(&buf->mutex);

}

void unlock_bufCAM(struct loop_bufCAM *buf)

{

pthread_mutex_unlock(&buf->mutex);

}

void release_loop_bufCAM(struct loop_bufCAM *buf)

{

pthread_mutex_destroy(&buf->mutex);

}

//循环buffer用

int porting_camera_init(void)

{

// printf("#######porting_camera_init()in------------>######## \n");

HISI_INFO(MODULE_PRINT_CAM, "(in)");

CHECK_MODULE_INIT_STATUS(PORT_MODULE_CAM);

SET_MODULE_INIT_STATUS(PORT_MODULE_CAM);

HISI_INFO(MODULE_PRINT_CAM,"(out)");

return IPANEL_OK;

}

int  porting_camera_exit(void)

{

HISI_INFO(MODULE_PRINT_CAM, "(in)");

CHECK_MODULE_EXIT_STATUS(PORT_MODULE_CAM);

SET_MODULE_EXIT_STATUS(PORT_MODULE_CAM);

HISI_INFO(MODULE_PRINT_CAM,"(out)");

return IPANEL_OK;

}

//打开摄像头采集数据

UINT32_T ipanel_porting_camera_open(IPANEL_VCODEC_TYPE_E type)

{

HISI_INFO(MODULE_PRINT_CAM, "(in)");

INT32_T ret;

INT32_T  s32ViPort = HI_UNF_VI_PORT1;

HI_UNF_VCODEC_TYPE_E enVencFmt = HI_UNF_VCODEC_TYPE_H264;

HI_UNF_VI_INPUT_MODE_E enViMode = HI_UNF_VI_MODE_USB_CAM;

if(type != IPANEL_VCODEC_TYPE_H264)

{

HISI_INFO(PORT_MODULE_CAM, "open type is not h264");

}

/*启动视频采集与编码*/

HIAPI_RUN(VIVenc_Init(s32ViPort, enViMode, &g_hCAMVi, enVencFmt, &g_hCAMVenc), ret);

if(ret ==HI_FAILURE)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)VIVenc_Init failed!!!");

return IPANEL_NULL;

}

g_whCAMVenc=HI_TRUE;//控制线程读取数据的while循环

// pthread_create(&g_thCAMVenc, HI_NULL, VencRoutine, (void*)(&g_hCAMVenc));

if(g_thCAMVenc == 0)

{

g_thCAMVenc = ipanel_porting_task_create("venc", VencRoutine, (void*)(&g_hCAMVenc), 5, 0x4000);

if(g_thCAMVenc == 0)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)task create failed");

goto LAB_ERR;

}

}

else

{

HISI_ERR(MODULE_PRINT_CAM, "(err)task exist");

goto LAB_ERR;

}

init_loop_bufCAM(PCAM_buf);

HISI_INFO(MODULE_PRINT_CAM, "(out)");

return g_hCAMVi;

LAB_ERR:

return -1;

}

/*

功能:读取视频数据

参数:

handle:设备句柄

buf:用于读取数据的buffer

len:要读取的数据长度

返回值:

实际读取到的数据长度。

*/

INT32_T ipanel_porting_camera_read(UINT32_T handle,unsigned char *buf,INT32_T len)

{

UINT32_T length = 0;

if(handle != g_hCAMVi)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)invalid handle 0x%x", handle);

return IPANEL_ERR;

}

HISI_INFO(MODULE_PRINT_CAM, "(in)");

#if 1

if(writing0 || writing1)//当有数据往循环buffer中写的时候,不读数据

{

goto LAB_OK;

}

if(!g_ReadStop)//在ioctl中控制停止和开始读数据

{

lock_bufCAM(PCAM_buf);

length=get_loop_bufCAM(PCAM_buf, buf, len);

unlock_bufCAM(PCAM_buf);

}

#else

HI_S32 ret = HI_FAILURE;

HI_UNF_VENC_STREAM_S vencStream;

ret = HI_UNF_VENC_AcquireStream(g_hCAMVenc, &vencStream, 0);

if(HI_SUCCESS != ret)

{

goto LAB_OK;

}

if(vencStream.u32SlcLen[0] > 0)

{

memcpy(buf, vencStream.pu8Addr[0], vencStream.u32SlcLen[0]);

length += vencStream.u32SlcLen[0];

}

if (vencStream.u32SlcLen[1] > 0)

{

memcpy(buf+length, vencStream.pu8Addr[1], vencStream.u32SlcLen[1]);

length += vencStream.u32SlcLen[1];

}

ret = HI_UNF_VENC_ReleaseStream(g_hCAMVenc, &vencStream);

if(HI_SUCCESS!=ret)

{

HISI_ERR(MODULE_PRINT_CAM, "HI_UNF_VENC_ReleaseStream fail!!! ret=0x%x",ret);

}

#endif

LAB_OK:

HISI_INFO(MODULE_PRINT_CAM, "(out)len:%d", length);

return length;

}

/********************************************************************************************************

功能:对视频采集设备实例进行一个操作,或者用于设置和获取视频采集设备实例的参数和属性

原型:INT32_T ipanel_porting_camera_ioctl(UINT32_T handle, IPANEL_CAMERA_IOCTL_e op, VOID * arg)

参数说明:

输入参数:

handle -- 视频采集设备实例句柄

op -- 操作命令

typedef enum

{

IPANEL_CAMERA_START = 1,

IPANEL_CAMERA_STOP = 2,

IPANEL_CAMERA_CLEAR_BUFFER = 3,

IPANEL_CAMERA_SET_PARAM = 4,

IPANEL_CAMERA_2_GRAPHIC_BUFFER = 5,

IPANEL_GRAPHIC_BUFFER_2_CAMERA = 6

} IPANEL_CAMERA_IOCTL_e;

arg -- 操作命令所带的参数,当传递枚举型或32位整数值时,arg可强制转换成对应数据类型。

op, arg取值见下表:

+---------------------+-------------------------+-----------------------------+

|  op                 |   arg                   |  说明                       |

+---------------------+-------------------------+-----------------------------+

| IPANEL_CAMERA_START |IPANEL_NULL              |启动视频采集。               |

+---------------------+-------------------------+-----------------------------+

| IPANEL_CAMERA_STOP  |IPANEL_NULL              |停止视频采集。               |

+---------------------+-------------------------+-----------------------------+

| IPANEL_CAMERA_      |IPANEL_NULL              |清空视频采集缓存             |

|   CLEAR_BUFFER      |                         |                             |

+---------------------+-------------------------+-----------------------------+

| IPANEL_CAMERA_      |指向                     |设置视频采集参数             |

|   SET_PARAM         |IPANEL_CAMERA_PARAMS_s   |                             |

|                     |结构的指针。             |                             |

|                     |typedef struct           |                             |

|                     |{                        |                             |

|                     |UINT32_T camera_flag;    |                             |

|                     |UINT32_T width;//要求采集的视频源宽度                  |

|                     |UINT32_T height;//要求采集的视频源高度                 |

|                     |IPANEL_VIDEO_STREAM_TYPE_e streamType;//要求采集的视频编码格式

|                     |UINT32_T frameRate;//要求采集的视频帧率                |

|                     |} IPANEL_CAMERA_PARAMS_s;|                             |

+---------------------+-------------------------+-----------------------------+

输出参数:无

返    回:

IPANEL_OK:成功

IPANEL_ERR:失败

********************************************************************************************************/

INT32_T ipanel_porting_camera_ioctl(UINT32_T       handle,IPANEL_CAMERA_IOCTL_e op, VOID    *arg)

{

HISI_INFO(MODULE_PRINT_CAM, "(in)op=%d",op);

if(handle != g_hCAMVi)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)invalid handle 0x%x", handle);

return IPANEL_ERR;

}

switch(op)

{

case IPANEL_CAMERA_START:

PCAM_buf->in = PCAM_buf->out = 0;

g_ReadStop=0;

usleep(50);

HISI_INFO(MODULE_PRINT_CAM, "IPANEL_CAMERA_START");

break;

case IPANEL_CAMERA_STOP:

g_ReadStop=1;

memset(PCAM_buf->buffer, 0, LOOP_BUFF_SIZE);

PCAM_buf->in = PCAM_buf->out = 0;

usleep(200);

HISI_INFO(MODULE_PRINT_CAM, "IPANEL_CAMERA_STOP");

break;

case IPANEL_CAMERA_CLEAR_BUFFER:

CleanBuf = HI_TRUE;

usleep(200);

memset(PCAM_buf->buffer, 0, LOOP_BUFF_SIZE);

PCAM_buf->in = PCAM_buf->out = 0;

CleanBuf = HI_FALSE;

HISI_INFO(MODULE_PRINT_CAM, "IPANEL_CAMERA_CLEAR_BUFFER");

break;

case IPANEL_CAMERA_SET_DISPLAY_RECT:

//设置视频窗口位置

HISI_INFO(PORT_MODULE_CAM, "set location");

porting_camera_set_location_by_rect(arg);

break;

default:

HISI_INFO(MODULE_PRINT_CAM, "no suppose now ...");

break;

}

LAB_OK:

HISI_INFO(MODULE_PRINT_CAM, "(out)");

return IPANEL_OK;

}

//关闭摄像头采集数据。

INT32_T ipanel_porting_camera_close(UINT32_T handle)

{

HISI_INFO(MODULE_PRINT_CAM, "(in)");

int ret=-1;

if(handle != g_hCAMVi)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)invalid handle 0x%x", handle);

return IPANEL_ERR;

}

g_whCAMVenc = HI_FALSE;

g_whCAMVi = HI_FALSE;

if(g_thCAMVenc!=0)

{

ret = ipanel_porting_task_destroy(g_thCAMVenc);

if(ret==0)

{

g_thCAMVenc = 0;

}

else

{

goto LAB_ERR;

}

}

else

{

goto LAB_ERR;

}

UsbCamDeinit(&g_stUSBCamArgs);

release_loop_bufCAM(PCAM_buf);

HI_ADP_VIVENC_DeInit(g_hCAMVi,g_hCAMVenc);

HISI_INFO(MODULE_PRINT_CAM, "(out)");

return IPANEL_OK;

LAB_ERR:

HISI_INFO(MODULE_PRINT_CAM, "(err)");

return -1;

}

INT32_T ipanel_porting_camera_set_notify(UINT32_T handle, IPANEL_CAMERA_NOTIFY fuc)

{

return 0;

}

UINT32_T porting_getVIhandle()

{

return g_hCAMVi;

}

static void* VencRoutine(void* args)

{

HI_S32 ret = HI_FAILURE;

HI_UNF_VENC_STREAM_S vencStream;

HI_HANDLE hVenc = *(HI_HANDLE*)args;

while(g_whCAMVenc)

{

if(HI_TRUE ==  CleanBuf)

{

usleep(1000*10);

continue;

}

ret = HI_UNF_VENC_AcquireStream(hVenc, &vencStream, 0);

if(HI_SUCCESS != ret)

{

usleep(10*1000);//10*1000

continue;

}

if(!g_ReadStop)

{

if(vencStream.u32SlcLen[0] > 0)

{

writing0=1;

lock_bufCAM(PCAM_buf);

put_loop_bufCAM(PCAM_buf, vencStream.pu8Addr[0], vencStream.u32SlcLen[0]);

unlock_bufCAM(PCAM_buf);

writing0=0;

}

if (vencStream.u32SlcLen[1] > 0)

{

writing1=1;

lock_bufCAM(PCAM_buf);

put_loop_bufCAM(PCAM_buf, vencStream.pu8Addr[1], vencStream.u32SlcLen[1]);

unlock_bufCAM(PCAM_buf);

writing1=0;

}

}

else

{

usleep(300);

}

ret = HI_UNF_VENC_ReleaseStream(hVenc, &vencStream);

if(HI_SUCCESS!=ret)

{

HISI_ERR(MODULE_PRINT_CAM, "HI_UNF_VENC_ReleaseStream fail!!! ret=0x%x",ret);

}

}

HISI_INFO(MODULE_PRINT_CAM, "out of the while of g_whCAMVenc");

return NULL;

}

/*********************************************************************

*******************************  USB cam *****************************

**********************************************************************/

UINT32_T UsbCamInit(USB_CAM_THREAD_ARG_S *pArgs)

{

INT32_T s32Ret,i;

struct v4l2_format fmt;

struct v4l2_buffer buf;

struct v4l2_capability cap;

struct v4l2_requestbuffers rb;

struct v4l2_streamparm *setfps;

enum v4l2_buf_type type;

INT32_T  fps=CAM_FPS;

int fdUsbCam;

HI_UNF_VI_ATTR_S        stViAttr;

HISI_INFO(MODULE_PRINT_CAM, "(in)");

//检查设备是否存在

s32Ret = access(UsbCamDev,F_OK);

if(IPANEL_OK != s32Ret)

{

s32Ret = access(TmpCamDev,F_OK);

if(IPANEL_OK != s32Ret)

{

HISI_INFO(PORT_MODULE_CAM, "(err)not found the device of video!!!");

return IPANEL_ERR;

}

}

fdUsbCam = open(UsbCamDev, O_RDWR | O_NONBLOCK, 0);//打开设备

if(-1 == fdUsbCam)

{

HISI_INFO(PORT_MODULE_CAM, "open %s failed!!!",UsbCamDev);

fdUsbCam = open(TmpCamDev,O_RDWR | O_NONBLOCK ,0);

if(HI_FAILURE == fdUsbCam)

{

HISI_ERR(PORT_MODULE_CAM, "open %s failed!!!",TmpCamDev);

return IPANEL_ERR;

}

HISI_INFO(PORT_MODULE_CAM, "open %s Ok.", TmpCamDev);

}

else

{

HISI_INFO(PORT_MODULE_CAM, "open %s Ok.", UsbCamDev);

}

s32Ret = ioctl(fdUsbCam, VIDIOC_QUERYCAP, &cap);

if (s32Ret < 0)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Error opening device %s: unable to query device.",device_name);

return -1;

}

HISI_INFO(MODULE_PRINT_CAM, "usb cam cap:0x%x.", cap.capabilities);

if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)

{

HISI_ERR(MODULE_PRINT_CAM,"(err)Error opening device %s: video capture not supported.",device_name);

return -1;

}

if (!(cap.capabilities & V4L2_CAP_STREAMING))

{

HISI_ERR(MODULE_PRINT_CAM, "(err)%s Not support streaming i/o", device_name);

return -1;

}

/* test format if it support */

memset(&fmt, 0, sizeof(struct v4l2_format));

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (ioctl(fdUsbCam, VIDIOC_G_FMT, &fmt) < 0)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)get format failed\n");

return -1;

}

else

{

HISI_INFO(MODULE_PRINT_CAM, "USB CAM's orignal FMT:");

HISI_INFO(MODULE_PRINT_CAM, "Width = %d", fmt.fmt.pix.width);

HISI_INFO(MODULE_PRINT_CAM, "Height = %d", fmt.fmt.pix.height);

HISI_INFO(MODULE_PRINT_CAM, "Image size = %d", fmt.fmt.pix.sizeimage);

HISI_INFO(MODULE_PRINT_CAM, "pixelformat = %d", fmt.fmt.pix.pixelformat);

HISI_INFO(MODULE_PRINT_CAM, "field = %d", fmt.fmt.pix.field);

if(V4L2_PIX_FMT_MJPEG == fmt.fmt.pix.pixelformat)

{

HISI_INFO(MODULE_PRINT_CAM, "V4L2_PIX_FMT_MJPEG\r");

}

else if(V4L2_PIX_FMT_YUYV == fmt.fmt.pix.pixelformat)

{

HISI_INFO(MODULE_PRINT_CAM, "V4L2_PIX_FMT_YUYV\r");

}

else

{

HISI_INFO(MODULE_PRINT_CAM, "fmt unknown\r");

}

pArgs->u32USBCamFmt = fmt.fmt.pix.pixelformat;

}

#if 1

/* set format in */

fmt.fmt.pix.width =  SAMPLE_VI_USB_CAM_WIDTH;

fmt.fmt.pix.height = SAMPLE_VI_USB_CAM_HEIGHT;

fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

s32Ret = ioctl(fdUsbCam, VIDIOC_S_FMT, &fmt);

if (s32Ret < 0)

{

printf("Unable to set format: %d, err:%d.\n",fmt.fmt.pix.pixelformat, errno);

return s32Ret;

}

if (ioctl(fdUsbCam, VIDIOC_G_FMT, &fmt) < 0)

{

printf("get format failed\n");

return -1;

}

else

{

HISI_INFO(MODULE_PRINT_CAM, "After set attr:");

HISI_INFO(MODULE_PRINT_CAM, "Width = %d", fmt.fmt.pix.width);

HISI_INFO(MODULE_PRINT_CAM, "Height = %d", fmt.fmt.pix.height);

HISI_INFO(MODULE_PRINT_CAM, "Image size = %d", fmt.fmt.pix.sizeimage);

HISI_INFO(MODULE_PRINT_CAM, "pixelformat = %d", fmt.fmt.pix.pixelformat);

if(V4L2_PIX_FMT_MJPEG == fmt.fmt.pix.pixelformat)

{

HISI_INFO(MODULE_PRINT_CAM, "V4L2_PIX_FMT_MJPEG\r");

}

else if(V4L2_PIX_FMT_YUYV == fmt.fmt.pix.pixelformat)

{

HISI_INFO(MODULE_PRINT_CAM, "V4L2_PIX_FMT_YUYV\r");

}

else

{

printf("fmt unknown\r\n");

}

}

#endif

setfps=(struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm));

memset(setfps, 0, sizeof(struct v4l2_streamparm));

setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

s32Ret = ioctl(fdUsbCam, VIDIOC_G_PARM, setfps);

if(s32Ret == 0)

{

HISI_INFO(MODULE_PRINT_CAM,"Frame rate:   %u/%u",

setfps->parm.capture.timeperframe.denominator, setfps->parm.capture.timeperframe.numerator);

}

else

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to read out current frame rate");

return -1;

}

if (setfps->parm.capture.timeperframe.numerator == 1

&& setfps->parm.capture.timeperframe.denominator == fps)

{

; /* OK ,fps is aready the value we want */

}

else

{

/* set framerate */

setfps->parm.capture.timeperframe.numerator=1;

setfps->parm.capture.timeperframe.denominator=fps; //

s32Ret = ioctl(fdUsbCam, VIDIOC_S_PARM, setfps);

if(s32Ret == -1)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to set frame rate");

return s32Ret;

}

s32Ret = ioctl(fdUsbCam, VIDIOC_G_PARM, setfps);

if(s32Ret == 0)

{

if (setfps->parm.capture.timeperframe.numerator != 1 ||setfps->parm.capture.timeperframe.denominator != fps)

{

HISI_INFO(MODULE_PRINT_CAM, "Frame rate:   %u/%u fps (requested frame rate %u fps is not supported by device)",

setfps->parm.capture.timeperframe.denominator,

setfps->parm.capture.timeperframe.numerator, fps);

}

else

{

HISI_INFO(MODULE_PRINT_CAM, "Frame rate:   %d fps", fps);

}

}

else

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to read out current frame rate");

return -1;

}

}

HISI_INFO(MODULE_PRINT_CAM, "USB CAM's output mode: %d", setfps->parm.output.outputmode);

/* request buffers */

memset(&rb, 0, sizeof(struct v4l2_requestbuffers));

rb.count = SAMPLE_USB_CAM_BUFFER_NUM;

rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

rb.memory = V4L2_MEMORY_MMAP;

s32Ret = ioctl(fdUsbCam, VIDIOC_REQBUFS, &rb);

if (s32Ret < 0)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to allocate buffers: %d.", errno);

return s32Ret;

}

/* map the buffers */

for (i = 0; i < SAMPLE_USB_CAM_BUFFER_NUM; i++)

{

memset(&buf, 0, sizeof(struct v4l2_buffer));

buf.index = i;

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

s32Ret = ioctl(fdUsbCam, VIDIOC_QUERYBUF, &buf);

if (s32Ret < 0)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to query buffer (%d).", errno);

return s32Ret;

}

HISI_INFO(MODULE_PRINT_CAM, "USB CAM's buffer length: %u offset: %u", buf.length,  buf.m.offset);

UsbCamBuff[i].length = buf.length;

UsbCamBuff[i].pAddr = mmap(NULL,buf.length, PROT_READ|PROT_WRITE, MAP_SHARED,fdUsbCam,buf.m.offset);

if (UsbCamBuff[i].pAddr == MAP_FAILED)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to map buffer (%d)", errno);

return -1;

}

HISI_INFO(MODULE_PRINT_CAM, "USB CAM Buffer %d mapped at address %p.", i, UsbCamBuff[i].pAddr);

}

HISI_INFO(MODULE_PRINT_CAM, "pArg->hVi %d",pArgs->hVi);

s32Ret = HI_UNF_VI_GetAttr(pArgs->hVi,&stViAttr);

if(HI_SUCCESS == s32Ret)

{

for(i=0;i<SAMPLE_USB_CAM_BUFFER_NUM;i++)

{

stViAttr.u32ViBufAddr = (HI_U32)UsbCamBuff[i].pAddr;

stViAttr.u32BufNum = i;

HISI_INFO(MODULE_PRINT_CAM, "654321stViAttr Buffer %p stViAttr enViPort 0X%x ,BUF_MGMT_E %d",\

stViAttr.u32ViBufAddr,stViAttr.enViPort,stViAttr.enBufMgmtMode);

s32Ret = HI_UNF_VI_SetAttr(pArgs->hVi,&stViAttr);

if(HI_SUCCESS != s32Ret)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to set vi buffer (%x).", s32Ret);

return s32Ret;

}

}

}

/* Queue the buffers. */

for (i = 0; i < SAMPLE_USB_CAM_BUFFER_NUM; ++i)

{

memset(&buf, 0, sizeof(struct v4l2_buffer));

buf.index = i;

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

s32Ret = ioctl(fdUsbCam, VIDIOC_QBUF, &buf);

if (s32Ret < 0)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to queue buffer (%d).", errno);

return s32Ret;

}

}

/*start camera capture */

type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;

s32Ret  = ioctl(fdUsbCam, VIDIOC_STREAMON, &type);

if (s32Ret < 0)

{

HISI_ERR(MODULE_PRINT_CAM, "(err)Unable to streamon (%d).", errno);

return s32Ret;

}

pArgs->UsbCamFd = fdUsbCam;

camera_attach_window(pArgs->hVi);

HISI_INFO(MODULE_PRINT_CAM,"(out)");

return HI_SUCCESS;

}

UINT32_T UsbCamDeinit(USB_CAM_THREAD_ARG_S *pArgs)

{

HISI_INFO(MODULE_PRINT_CAM,"(in)");

enum v4l2_buf_type type;

INT32_T s32Ret, i;

type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;

s32Ret  = ioctl(pArgs->UsbCamFd, VIDIOC_STREAMOFF, &type);

if (s32Ret < 0)

{

printf("Unable to streamoff (%d).\n", errno);

return s32Ret;

}

for (i = 0; i < SAMPLE_USB_CAM_BUFFER_NUM; i++)

{

munmap(UsbCamBuff[i].pAddr, UsbCamBuff[i].length);

}

close(pArgs->UsbCamFd);

camera_detach_window(pArgs->hVi);

HISI_INFO(MODULE_PRINT_CAM,"(out)");

return HI_SUCCESS;

}

void *UsbCamRoutine(void* args)

{

HISI_INFO(MODULE_PRINT_CAM, "(in)");

//video抓取

HI_S32  buf_index = 0;

HI_S32  s32Ret;

HI_U32  totalFrame = 0;

HI_U32  releaseFrame =0 ;

struct v4l2_buffer buf;

HI_U32  j,fail_cnt =0;

HI_U32  tagFrame = 0,reopen_flag = 0;

HI_UNF_VI_BUF_S struViBuf;

USB_CAM_THREAD_ARG_S *pArgs = (USB_CAM_THREAD_ARG_S*)args;

HI_HANDLE hVi = pArgs->hVi;

while(g_whCAMVi)

{

if (HI_SUCCESS == UsbCamInit(pArgs))

{

break;

}

else

{

UsbCamDeinit(pArgs);

usleep(100000);

}

}

while(g_whCAMVi)

{

memset(&buf,0,sizeof(buf));

buf.type    =V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory  =V4L2_MEMORY_MMAP;

buf.index   =buf_index ;

//读取缓存

s32Ret=ioctl(pArgs->UsbCamFd, VIDIOC_DQBUF, &buf);

if( s32Ret < 0 )

{

/*启用下边这段会导致视频采集在本地播放很卡*/

usleep(10*1000); //10*10000

fail_cnt++;

if(fail_cnt >= 300) //300

{

HISI_INFO(MODULE_PRINT_CAM, "ioctl failed over 300 times.");

UsbCamDeinit(pArgs);

UsbCamInit(pArgs);

tagFrame = totalFrame;

fail_cnt = 0;

// reopen_flag = 1;

}

}

else

{

totalFrame++;

fail_cnt = 0;

if (V4L2_PIX_FMT_YUYV == pArgs->u32USBCamFmt)

{

struViBuf.enPixelFormat = HI_UNF_FORMAT_YUV_PACKAGE_YUYV;

struViBuf.u32Stride[0] = SAMPLE_VI_USB_CAM_WIDTH * 2;

struViBuf.pVirAddr[0] = UsbCamBuff[buf.index].pAddr;

s32Ret = HI_UNF_VI_PutFrame(hVi, &struViBuf);

}

else

{

printf("fmt unknown\r\n");

}

buf_index  = (buf_index +1) % SAMPLE_USB_CAM_BUFFER_NUM;

}

//Always try to get frame from vi

s32Ret = HI_UNF_VI_GetFrame(hVi, &struViBuf);

if(s32Ret == HI_SUCCESS)

{

if(!reopen_flag)

{

for(j = 0; j < SAMPLE_USB_CAM_BUFFER_NUM; j++)

{

if(struViBuf.pVirAddr[0] == UsbCamBuff[j].pAddr)

{

buf.index= j;

releaseFrame++;

//Reput buffer into queue

s32Ret=ioctl(pArgs->UsbCamFd, VIDIOC_QBUF, &buf);

if( s32Ret== -1)

{

printf("EnQ Cam buffer error:%d\n", s32Ret);

break;

}

}

}

}

else

{

releaseFrame++;

if(releaseFrame == tagFrame)

{

reopen_flag = 0;

tagFrame = 0;

}

}

}

}

//    UsbCamDeinit(pArgs);

HISI_INFO(MODULE_PRINT_CAM,"(out)");

}

/*

UINT32_T  phVi;//视频输入句柄

UINT32_T  phVenc;//视频编码通道

*/

INT32_T VIVenc_Init(HI_UNF_VI_E enViPort, HI_UNF_VI_INPUT_MODE_E enViMode, UINT32_T *phVi, HI_UNF_VCODEC_TYPE_E enVencFmt, UINT32_T *phVenc)

{

HISI_INFO(MODULE_PRINT_CAM, "(in)");

INT32_T                  ret = HI_SUCCESS;

UINT32_T               hVi;

UINT32_T               hVenc;

HI_UNF_VI_ATTR_S        stViAttr;

HI_UNF_VENC_CHN_ATTR_S  stVeAttr;

HI_UNF_VENC_CHN_ATTR_S *pstVeAttr=&stVeAttr;

HIAPI_RUN_RETURN(HI_UNF_VI_Init());

HIAPI_RUN_RETURN(HI_UNF_VENC_Init());

HIAPI_RUN_RETURN(HI_UNF_VI_GetDefaultAttr(&stViAttr));

stViAttr.enViPort = enViPort;

stViAttr.enInputMode = enViMode;

if (HI_UNF_VI_MODE_USB_CAM == enViMode)

{

stViAttr.stInputRect.s32X = 0;

stViAttr.stInputRect.s32Y = 0;

stViAttr.stInputRect.s32Width = SAMPLE_VI_USB_CAM_WIDTH;

stViAttr.stInputRect.s32Height = SAMPLE_VI_USB_CAM_HEIGHT;

stViAttr.enStoreMethod = HI_UNF_VI_STORE_METHOD_PKYUV;

stViAttr.enStoreMode = HI_UNF_VI_STORE_FRAME;

stViAttr.enBufMgmtMode = HI_UNF_VI_BUF_MMAP;

stViAttr.u32YStride = SAMPLE_VI_USB_CAM_WIDTH * 2;

stViAttr.u32CStride = 0;

stViAttr.u32BufNum = 6;

}

else

{

HISI_INFO(MODULE_PRINT_CAM,"enViMode NOT support NOW..");

}

HIAPI_RUN(HI_UNF_VI_Create(&stViAttr, &(hVi)), ret);

if (ret != HI_SUCCESS)

{

HISI_INFO(MODULE_PRINT_CAM,"HI_UNF_VI_Create fail ,errno=0x%x",ret);

HI_UNF_VI_DeInit();

return ret;

}

HIAPI_RUN(HI_UNF_VENC_GetDefaultAttr(pstVeAttr), ret);

pstVeAttr->enVencType = enVencFmt;

pstVeAttr->u32Height = stViAttr.stInputRect.s32Height;

pstVeAttr->u32Width = stViAttr.stInputRect.s32Width;

pstVeAttr->bSlcSplitEn = HI_FALSE;

pstVeAttr->u32SplitSize = 1024;

pstVeAttr->u32Gop = 300;

pstVeAttr->u32Qlevel = 0;

pstVeAttr->u32InputFrmRate = 25;

pstVeAttr->u32TargetFrmRate = 24;

pstVeAttr->u32TargetBitRate =1768*1024;

if (HI_UNF_VI_MODE_USB_CAM == enViMode)

{

pstVeAttr->enYuvStoreType   = HI_UNF_VENC_STORE_PACKAGE;

pstVeAttr->enYuvSampleType  = HI_UNF_VENC_YUV_422;

pstVeAttr->u32InputFrmRate  = 30;

pstVeAttr->u32TargetFrmRate = 30;

}

else

{

HISI_INFO(MODULE_PRINT_CAM,"enViMode NOT support NOW.");

}

pstVeAttr->bSendToNet = HI_FALSE;

HIAPI_RUN(HI_UNF_VENC_CreateChn(&hVenc, pstVeAttr), ret);

if (ret != HI_SUCCESS)

{

HISI_ERR(MODULE_PRINT_CAM, "HI_UNF_VENC_CreateChn fail!!!,errno=0x%x",ret);

HI_UNF_VENC_DeInit();

HI_UNF_VI_DeInit();

return ret;

}

HIAPI_RUN(HI_UNF_VENC_AttachInput(hVenc, hVi), ret);

if (ret != HI_SUCCESS)

{

HI_UNF_VENC_DestroyChn(hVenc);

HI_UNF_VENC_DeInit();

HI_UNF_VI_DeInit();

return ret;

}

HIAPI_RUN(HI_UNF_VENC_Start(hVenc), ret);

if (ret != HI_SUCCESS)

{

HI_UNF_VENC_DetachInput(hVenc, hVi);

HI_UNF_VENC_DestroyChn(hVenc);

HI_UNF_VENC_DeInit();

return ret;

}

*phVi = hVi;

*phVenc = hVenc;

g_stUSBCamArgs.hVi = hVi;

g_whCAMVi = HI_TRUE;

//    pthread_create(&g_thCAMVi, HI_NULL, UsbCamRoute, (void*)(&g_stUSBCamArgs));

if(g_thCAMVi==0)

{

g_thCAMVi = ipanel_porting_task_create("ucam", UsbCamRoutine, (void*)(&g_stUSBCamArgs), 5, 0x2000);

if(g_thCAMVi==0) goto LAB_ERR;

}

else

{

goto LAB_ERR;

}

HISI_INFO(MODULE_PRINT_CAM, "(out)");

return ret;

LAB_ERR:

HI_ADP_VIVENC_DeInit(hVi, hVenc);

HISI_ERR(MODULE_PRINT_CAM, "(err)");

return -1;

}

INT32_T HI_ADP_VIVENC_DeInit(UINT32_T hVi, UINT32_T hVenc)

{

INT32_T  ret = HI_SUCCESS;

HIAPI_RUN(HI_UNF_VENC_Stop(hVenc), ret);

HIAPI_RUN(HI_UNF_VENC_DetachInput(hVenc,hVi), ret);

HIAPI_RUN(HI_UNF_VENC_DestroyChn(hVenc), ret);

HIAPI_RUN(HI_UNF_VENC_DeInit(), ret);

if (g_thCAMVi)

{

g_whCAMVi = HI_FALSE;

ret = ipanel_porting_task_destroy(g_thCAMVi);

if(ret==0)

{

g_thCAMVi = 0;

}

}

HIAPI_RUN(HI_UNF_VI_Destroy(hVi), ret);

HIAPI_RUN(HI_UNF_VI_DeInit(), ret);

return ret;

}

HI_HANDLE camera_attach_window(HI_HANDLE vihandle)

{

INT32_T ret;

HI_HANDLE winhdl;

HI_UNF_WINDOW_ATTR_S win_attr;

HI_UNF_ENC_FMT_E enc_format = HI_UNF_ENC_FMT_720P_50;

HI_U32 width = 0, height = 0;

ret = HI_UNF_VO_GetWindowAttr(porting_display_get_video_window(), &win_attr);

if (HI_SUCCESS != ret)

{

HISI_ERR(MODULE_PRINT_CAM,"(err)HI_UNF_VO_GetWindowAttr error:0x%x", ret);

return -1;

}

win_attr.enVo = HI_UNF_VO_HD0;

win_attr.bVirtual = 0;

win_attr.enVideoFormat = HI_UNF_FORMAT_YUV_PACKAGE_YUYV;

win_attr.enAspectRatio = HI_UNF_ASPECT_RATIO_16TO9;

win_attr.enAspectCvrs = HI_UNF_ASPECT_CVRS_IGNORE;

win_attr.stInputRect.s32X = 0;

win_attr.stInputRect.s32Y = 0;

win_attr.stInputRect.s32Width = 1280;

win_attr.stInputRect.s32Height = 720;

win_attr.stOutputRect.s32X = win_attr.stOutputRect.s32X+win_attr.stOutputRect.s32Width*3/4;

win_attr.stOutputRect.s32Y = win_attr.stOutputRect.s32Y+win_attr.stOutputRect.s32Height*3/4;

win_attr.stOutputRect.s32Width = win_attr.stOutputRect.s32Width/4;

win_attr.stOutputRect.s32Height = win_attr.stOutputRect.s32Height/4;

ret = HI_UNF_VO_CreateWindow(&win_attr, &winhdl);

if(ret != IPANEL_OK)

{

HISI_ERR(MODULE_PRINT_CAM,"(err)creat VOIP1 window fail!!!,errno=0x%x",ret);

return IPANEL_ERR;

}

ret = HI_UNF_VO_SetWindowZorder(winhdl, HI_LAYER_ZORDER_MOVETOP);

ret = HI_UNF_VO_AttachWindow(winhdl, vihandle);

if(ret != IPANEL_OK)

{

HISI_ERR(MODULE_PRINT_CAM,"(err)HI_UNF_VO_SetWindowZorder fail!!!,errno=0x%x",ret);

return IPANEL_ERR;

}

ret = HI_UNF_VO_SetWindowEnable(winhdl, HI_TRUE);

if(ret != IPANEL_OK)

{

HISI_ERR(MODULE_PRINT_CAM,"(err)HI_UNF_VO_SetWindowZorder fail!!!,errno=0x%x",ret);

return IPANEL_ERR;

}

g_Winhdl = winhdl;

return winhdl;

}

void camera_detach_window(HI_HANDLE vihandle)

{

HI_UNF_VO_SetWindowEnable(g_Winhdl, HI_FALSE);

HI_UNF_VO_DetachWindow(g_Winhdl, vihandle);

HI_UNF_VO_DestroyWindow(g_Winhdl);

g_Winhdl = 0;

}

int porting_camera_set_location(    HI_UNF_WINDOW_ATTR_S *win_attr)

{

if(g_Winhdl==0)

{

return 0;

}

int ret;

HI_UNF_WINDOW_ATTR_S attr;

ret = HI_UNF_VO_GetWindowAttr(g_Winhdl, &attr);

if (HI_SUCCESS != ret)

{

HISI_ERR(MODULE_PRINT_CAM,"(err)HI_UNF_VO_GetWindowAttr error:0x%x", ret);

goto LAB_ERR;

}

attr.stOutputRect.s32X = win_attr->stOutputRect.s32X+win_attr->stOutputRect.s32Width*3/4;

attr.stOutputRect.s32Y = win_attr->stOutputRect.s32Y+win_attr->stOutputRect.s32Height*3/4;

attr.stOutputRect.s32Width = win_attr->stOutputRect.s32Width/4;

attr.stOutputRect.s32Height = win_attr->stOutputRect.s32Height/4;

ret = HI_UNF_VO_SetWindowAttr(g_Winhdl, &attr);

if (HI_SUCCESS != ret)

{

HISI_ERR(MODULE_PRINT_CAM,"(err)HI_UNF_VO_SetWindowAttr error:0x%x", ret);

goto LAB_ERR;

}

return IPANEL_OK;

LAB_ERR:

return IPANEL_ERR;

}

void porting_camera_set_location_by_rect(void *arg)

{

IPANEL_RECT *rect;

HI_UNF_WINDOW_ATTR_S attr;

int ret;

rect=(IPANEL_RECT *)arg;

if(g_Winhdl==0&&rect!=NULL)

{

return ;

}

ret = HI_UNF_VO_GetWindowAttr(g_Winhdl, &attr);

if (HI_SUCCESS != ret)

{

HISI_ERR(PORT_MODULE_CAM,"(err)HI_UNF_VO_GetWindowAttr error:0x%x", ret);

return;

}

attr.stOutputRect.s32X = rect->x;

attr.stOutputRect.s32Y = rect->y;

attr.stOutputRect.s32Width = rect->w;

attr.stOutputRect.s32Height = rect->h;

ret = HI_UNF_VO_SetWindowAttr(g_Winhdl, &attr);

if (HI_SUCCESS != ret)

{

HISI_ERR(PORT_MODULE_CAM,"(err)HI_UNF_VO_SetWindowAttr error:0x%x", ret);

return;

}

return;

}

V4L2摄像头取数据程序相关推荐

  1. C语言高级应用---操作linux下V4L2摄像头应用程序

    目录(?)[-]采集方式V4L2操作流程点击这个网址说得很详细了这里不多说httpbaikebaiducomview5494174htm我们都知道,想要驱动Linux下的摄像头,其实很简单,照着V4L ...

  2. 朋友开网店 做个抓取数据的小程序

    朋友开网店需要填充初期的数据.  专门做了一个抓取数据的小程序.分享一下. private void button1_Click(object sender, EventArgs e)         ...

  3. 【爬虫+数据可视化毕业设计:英雄联盟数据爬取及可视化分析,python爬虫可视化/数据分析/大数据/大数据屏/数据挖掘/数据爬取,程序开发-哔哩哔哩】

    [爬虫+数据可视化毕业设计:英雄联盟数据爬取及可视化分析,python爬虫可视化/数据分析/大数据/大数据屏/数据挖掘/数据爬取,程序开发-哔哩哔哩] https://b23.tv/TIoy6hj

  4. 微信小程序从后台的SQL SERVER取数据

    一值搞CS模式的ERP开发,不会BS,不会CSS等.学习微信小程序几天,水平很菜,网上找了好久,没找到微信小程序从后台的SQL SERVER取数据的例子,好失望啊. 听说微信小程序可以访问webser ...

  5. 【【数据可视化毕业设计:差旅数据可视化分析,python爬虫可视化/数据分析/大数据/大数据屏/数据挖掘/数据爬取,程序开发-哔哩哔哩】-哔哩哔哩】 https://b23.tv/iTt30QG

    [[数据可视化毕业设计:差旅数据可视化分析,python爬虫可视化/数据分析/大数据/大数据屏/数据挖掘/数据爬取,程序开发-哔哩哔哩]-哔哩哔哩] https://b23.tv/iTt30QG ht ...

  6. 网络爬虫入门:网络爬虫的目的,企业获取数据的方式,可以用于做爬虫的程序语言,爬虫爬取数据的步骤

    目录 爬取数据的目的: 1.获取大量数据,用于做数据分析 2.公司项目的测试数据,公司业务所需数据 企业获取数据的方式 1.公司自有数据 2.第三方数据平台购买(数据堂,贵阳大数据交易所) 3.爬虫爬 ...

  7. 如何在微信小程序中爬取数据

    如何在微信小程序中爬取数据 下载Charles 在Charles中点击Help -> SSL Proxying -> Install Charles Root Certificate 然后 ...

  8. 利用python编写爬虫程序,从招聘网站上爬取数据,将数据存入到MongoDB数据库中,将存入的数据作一定的数据清洗后做数据分析,最后将分析的结果做数据可视化

    教程演示 创建爬虫项目 编写需要爬取的字段(items.py) 编写spider文件(wuyou.py) 编写数据库连接(pipelines.py) 编写反爬措施(settings.py) Mongo ...

  9. 【正点原子Linux连载】第二十章 V4L2摄像头应用编程-摘自【正点原子】I.MX6U嵌入式Linux C应用编程指南V1.1

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  10. 我们一起学linux之V4L2摄像头应用流程

    一.概述 Video for Linuxtwo(Video4Linux2)简称V4L2,是V4L的改进版.V4L2是linux操作系统下用于采集图片.视频和音频数据的API接口,配合适当的视频采集设备 ...

最新文章

  1. 关于CSDN不给任何通知强制关闭我的6年博客,我深表痛心
  2. Openstack_SQLAlchemy 修改数据库的表结构
  3. 【流媒体开发】VLC Media Player - Android 平台源码编译 与 二次开发详解 (提供详细800M下载好的编译源码及eclipse可调试播放器源码下载)
  4. python中set和dict类型_python从菜鸟到小仙的成长之路-----Dict和Set类型篇
  5. php ajax工作原理,AJAX实现页面无刷新操作原理解析
  6. 无法加载 DLL“SQLite.Interop.DLL”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。...
  7. 性能测试流程_流性能
  8. 工作237:vuex取值
  9. Fiddler设置抓一个域名下个包
  10. vscode 语法检查_Jenkins 声明式流水线的语法错误检查
  11. element布局容器大小_Flutter完整开发实战详解(十六、详解自定义布局实战)
  12. mysql内容_mysql 的基本内容
  13. 王彪20162321 2016-2017-2 《程序设计与数据结构》第4周学习总结
  14. java考试系统倒计时的实现_(Java程序设计)第11章设计考试系统中的倒计时.ppt
  15. C#基础 控制台应用程序(一)介绍
  16. 基于python的网络爬虫系统的设计与实现
  17. Android手机型号及产品名
  18. 简支梁内力的计算机分析程序,各种静定梁内力的计算机模拟分析.pdf
  19. 单片机一键开关机硬件电路
  20. 设计师都在用这几个免费素材网站,赶紧马住

热门文章

  1. 键盘映射keybmap工具使用
  2. win10下能够用的键盘映射工具? win10 下按键像mac一样
  3. uiswitch样式_可变大小、颜色边框、样式的UISwitch
  4. 《电子商务安全》考试重点/学习重点
  5. MySQL sql语句总结
  6. 数据库变为可疑_SQL Server 2008R2 数据库出现“可疑”导致无法访问解决办法
  7. 解决求平均值出现加和导致的溢出问题
  8. 波士顿房价数据集 Boston house prices dataset
  9. Flexsim——初学AGV必看的知识点(如何解决AGV在不同区域speed不同)
  10. 08.存储Cinder→5.场景学习→02.Create Volume→1.cinder-api处理过程