当前位置: 首页 > news >正文

邯郸做网站服务商/怎么创作自己的网站

邯郸做网站服务商,怎么创作自己的网站,惠州网站设计方案,商场网站建设公司1.0&#xff1a;client.c抓取帧并保存为PNG #include <stdio.h> // 标准输入输出库 #include <stdlib.h> // 标准库&#xff0c;包含内存分配等函数 #include <string.h> // 字符串操作库 #include <linux/videodev2.h> // V4L2 视频设备…

 1.0:client.c抓取帧并保存为PNG

#include <stdio.h>      // 标准输入输出库
#include <stdlib.h>     // 标准库,包含内存分配等函数
#include <string.h>     // 字符串操作库
#include <linux/videodev2.h> // V4L2 视频设备接口库
#include <sys/ioctl.h>  // 输入输出控制库
#include <fcntl.h>      // 文件控制定义
#include <unistd.h>     // UNIX 标准定义
#include <sys/mman.h>   // 内存映射库
#include <png.h>        // PNG 图像处理库// 定义摄像头设备文件和图像分辨率
#define CAM_DEV "/dev/video0" // 摄像头设备文件路径
#define WIDTH 640             // 图像宽度
#define HEIGHT 480            // 图像高度
#define NB_BUFFER 4           // 缓冲区数量// 定义用于存储图像数据的结构体
struct pic_data {unsigned char *tmpbuffer[NB_BUFFER];  // 存储每个缓冲区的指针unsigned int tmpbytesused[NB_BUFFER]; // 存储每个缓冲区的实际字节数
} pic;// 定义摄像头文件描述符
int cam_fd;// 声明函数
int v4l2_init(void);         // 初始化摄像头
int v4l2Grab(void);          // 抓取图像
int v4l2_close(void);        // 关闭摄像头
int CLAMP(int value, int min, int max); // 辅助函数,用于限制数值范围
int yuv422_rgb24(unsigned char *yuv_buf, unsigned char *rgb_buf, unsigned int width, unsigned int height); // YUV422 转 RGB24
void write_data_to_png(const char *png_name, png_uint_32 width, png_uint_32 height, png_bytepp data, int color_type); // 将 RGB 数据写入 PNG 文件// 定义用于存储 RGB 数据的结构体
typedef struct pixel_RGB {png_byte red, green, blue; // 每个像素的红、绿、蓝分量
} pixel_RGB;int main(int argc, char* argv[]) {// 初始化摄像头if (v4l2_init() == -1) {fprintf(stderr, "Failed to initialize camera.\n");return -1;}// 从摄像头抓取图像if (v4l2Grab() == -1) {fprintf(stderr, "Failed to grab image from camera.\n");v4l2_close();return -1;}// 分配 RGB 缓冲区unsigned char *rgb_buf = (unsigned char *)malloc(WIDTH * HEIGHT * 3);if (!rgb_buf) {fprintf(stderr, "Failed to allocate RGB buffer.\n");v4l2_close();return -1;}// 将 YUV 数据转换为 RGB 数据yuv422_rgb24(pic.tmpbuffer[0], rgb_buf, WIDTH, HEIGHT);// 分配 PNG 图像数据pixel_RGB *image_data_rgb = calloc(WIDTH * HEIGHT, sizeof(pixel_RGB));if (!image_data_rgb) {fprintf(stderr, "Failed to allocate image data for PNG.\n");free(rgb_buf);v4l2_close();return -1;}// 将 RGB 数据复制到 PNG 图像数据结构体中for (unsigned int i = 0; i < WIDTH * HEIGHT; i++) {image_data_rgb[i].red = rgb_buf[i * 3 + 2];image_data_rgb[i].green = rgb_buf[i * 3 + 1];image_data_rgb[i].blue = rgb_buf[i * 3 + 0];}// 保存为 PNG 图像const char *png_name = "camera_image.png";write_data_to_png(png_name, WIDTH, HEIGHT, (png_bytepp)image_data_rgb, PNG_COLOR_TYPE_RGB);// 释放资源free(rgb_buf);free(image_data_rgb);v4l2_close();return 0;
}// 初始化摄像头
int v4l2_init(void) {int i;int ret = 0;// 打开摄像头设备if ((cam_fd = open(CAM_DEV, O_RDWR)) == -1) {perror("ERROR opening V4L interface.");return -1;}// 判断设备是否为摄像头struct v4l2_capability cam_cap;if (ioctl(cam_fd, VIDIOC_QUERYCAP, &cam_cap) == -1) {perror("Error opening device %s: unable to query device.");return -1;}if ((cam_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {perror("ERROR video capture not supported.");return -1;}// 设置输出参数struct v4l2_format v4l2_fmt;v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;v4l2_fmt.fmt.pix.width = WIDTH;v4l2_fmt.fmt.pix.height = HEIGHT;v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;if (ioctl(cam_fd, VIDIOC_S_FMT, &v4l2_fmt) == -1) {perror("ERROR camera VIDIOC_S_FMT Failed.");return -1;}// 检查参数是否设置成功if (ioctl(cam_fd, VIDIOC_G_FMT, &v4l2_fmt) == -1) {perror("ERROR camera VIDIOC_G_FMT Failed.");return -1;}if (v4l2_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {printf("Set VIDIOC_S_FMT successful\n");}// 请求缓冲区存储图像数据struct v4l2_requestbuffers v4l2_req;v4l2_req.count = NB_BUFFER;v4l2_req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;v4l2_req.memory = V4L2_MEMORY_MMAP;if (ioctl(cam_fd, VIDIOC_REQBUFS, &v4l2_req) == -1) {perror("ERROR camera VIDIOC_REQBUFS Failed.");return -1;}// 开始内存映射struct v4l2_buffer v4l2_buf;v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;v4l2_buf.memory = V4L2_MEMORY_MMAP;for (i = 0; i < NB_BUFFER; i++) {v4l2_buf.index = i;if (ioctl(cam_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {perror("Unable to query buffer.");return -1;}pic.tmpbuffer[i] = mmap(NULL, v4l2_buf.length, PROT_READ, MAP_SHARED, cam_fd, v4l2_buf.m.offset);if (pic.tmpbuffer[i] == MAP_FAILED) {perror("Unable to map buffer.");return -1;}if (ioctl(cam_fd, VIDIOC_QBUF, &v4l2_buf) < 0) {perror("Unable to queue buffer.");return -1;}}// 开启流输入int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (ioctl(cam_fd, VIDIOC_STREAMON, &type) < 0) {perror("Unable to start capture.");return -1;}return 0;
}//抓取图像
int v4l2Grab(void) {// 获取图像struct v4l2_buffer buff;buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buff.memory = V4L2_MEMORY_MMAP;if (ioctl(cam_fd, VIDIOC_DQBUF, &buff) < 0) {printf("camera VIDIOC_DBUF Failed.\n");return -1;}pic.tmpbytesused[buff.index] = buff.bytesused;printf("size : %d\n", pic.tmpbytesused[buff.index]);// 保存图像int jpg_fd = open("v4l2.yuyv", O_RDWR | O_CREAT, 00700);if (jpg_fd == -1) {printf("open ipg Failed!\n");return -1;}int writesize = write(jpg_fd, pic.tmpbuffer[buff.index], pic.tmpbytesused[buff.index]);printf("Write successfully size : %d\n", writesize);close(jpg_fd);// 将缓冲区重新入队列if (ioctl(cam_fd, VIDIOC_QBUF, &buff) < 0) {printf("camera VIDIOC_QBUF Failed.");return -1;}return 0;
}//关闭摄像头
int v4l2_close(void) {// 解除内存映射struct v4l2_buffer v4l2_buf;v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;v4l2_buf.memory = V4L2_MEMORY_MMAP;for (int i = 0; i < NB_BUFFER; i++) {v4l2_buf.index = i;if (ioctl(cam_fd, VIDIOC_QUERYBUF, &v4l2_buf) == 0) {munmap(pic.tmpbuffer[i], v4l2_buf.length);}}close(cam_fd);return 0;
}//YUV422 转 RGB24
int yuv422_rgb24(unsigned char *yuv_buf, unsigned char *rgb_buf, unsigned int width, unsigned int height) {unsigned int i, j;unsigned char y0, y1, u, v;int r, g, b; // 使用 int 类型进行中间计算,以处理溢出问题for (i = 0; i < height; i++) {for (j = 0; j < width; j += 2) {// 提取 YUV 组件y0 = yuv_buf[i * width * 2 + j * 2];   // 第一个像素的 Y 分量u  = yuv_buf[i * width * 2 + j * 2 + 1]; // U 是两个像素共享的y1 = yuv_buf[i * width * 2 + j * 2 + 2]; // 第二个像素的 Y 分量v  = yuv_buf[i * width * 2 + j * 2 + 3]; // V 是两个像素共享的// 转换第一个像素r = (int)(y0 + 1.402 * (v - 128));g = (int)(y0 - 0.344 * (u - 128) - 0.714 * (v - 128));b = (int)(y0 + 1.772 * (u - 128));// 限制并赋值到 RGB 缓冲区rgb_buf[(i * width + j) * 3 + 0] = (unsigned char)CLAMP(b, 0, 255);rgb_buf[(i * width + j) * 3 + 1] = (unsigned char)CLAMP(g, 0, 255);rgb_buf[(i * width + j) * 3 + 2] = (unsigned char)CLAMP(r, 0, 255);// 转换第二个像素,使用相同的 UV 值r = (int)(y1 + 1.402 * (v - 128));g = (int)(y1 - 0.344 * (u - 128) - 0.714 * (v - 128));b = (int)(y1 + 1.772 * (u - 128));// 限制并赋值到 RGB 缓冲区rgb_buf[(i * width + j + 1) * 3 + 0] = (unsigned char)CLAMP(b, 0, 255);rgb_buf[(i * width + j + 1) * 3 + 1] = (unsigned char)CLAMP(g, 0, 255);rgb_buf[(i * width + j + 1) * 3 + 2] = (unsigned char)CLAMP(r, 0, 255);}}return 0;
}// 辅助函数:限制数值范围
int CLAMP(int value, int min, int max) {if (value < min) return min;if (value > max) return max;return value;
}//将 RGB 数据写入 PNG 文件
void write_data_to_png(const char *png_name, png_uint_32 width, png_uint_32 height, png_bytepp data, int color_type) {FILE *fp = fopen(png_name, "wb");if (!fp) {perror("Error opening PNG file for writing");return;}png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);if (!png) {perror("Error creating PNG write struct");fclose(fp);return;}png_infop info = png_create_info_struct(png);if (!info) {perror("Error creating PNG info struct");png_destroy_write_struct(&png, NULL);fclose(fp);return;}png_init_io(png, fp);png_set_IHDR(png, info, width, height, 8, color_type, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);png_write_info(png, info);// 分配行指针png_bytep *row_pointers = malloc(height * sizeof(png_bytep));if (!row_pointers) {perror("Error allocating row pointers");png_destroy_write_struct(&png, &info);fclose(fp);return;}// 分配每行的内存for (unsigned int i = 0; i < height; ++i) {row_pointers[i] = (png_bytep)&(((pixel_RGB *)data)[i * width]);}png_write_image(png, row_pointers);png_write_end(png, NULL);png_destroy_write_struct(&png, &info);fclose(fp);free(row_pointers);
}

更:客户端传获取到的图像给服务器

客户端:

client.c
#include <png.h>
#include "client.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <linux/videodev2.h>// 摄像头文件描述符
int cam_fd;// 用于存储图像数据的结构体
/*
struct pic_data {unsigned char *tmpbuffer[NB_BUFFER];unsigned int tmpbytesused[NB_BUFFER];
} pic;
*/// 初始化摄像头的函数
int v4l2_init(void) {int i;// 打开摄像头设备if ((cam_fd = open(CAM_DEV, O_RDWR)) == -1) {perror("打开V4L接口出错");return -1;}// 检查设备是否为摄像头struct v4l2_capability cam_cap;if (ioctl(cam_fd, VIDIOC_QUERYCAP, &cam_cap) == -1) {perror("打开设备时查询设备能力出错");return -1;}if ((cam_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {perror("不支持视频捕获");return -1;}// 设置输出参数struct v4l2_format v4l2_fmt;v4l2_fmt.type = V4L2_CAP_VIDEO_CAPTURE;v4l2_fmt.fmt.pix.width = WIDTH;v4l2_fmt.fmt.pix.height = HEIGHT;v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;if (ioctl(cam_fd, VIDIOC_S_FMT, &v4l2_fmt) == -1) {perror("设置摄像头格式失败");return -1;}// 检查参数是否设置成功if (ioctl(cam_fd, VIDIOC_G_FMT, &v4l2_fmt) == -1) {perror("获取摄像头格式失败");return -1;}if (v4l2_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {printf("设置VIDIOC_S_FMT成功\n");}// 请求缓冲区以存储图像数据struct v4l2_requestbuffers v4l2_req;v4l2_req.count = NB_BUFFER;v4l2_req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;v4l2_req.memory = V4L2_MEMORY_MMAP;if (ioctl(cam_fd, VIDIOC_REQBUFS, &v4l2_req) == -1) {perror("请求摄像头缓冲区失败");return -1;}// 映射内存struct v4l2_buffer v4l2_buf;v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;v4l2_buf.memory = V4L2_MEMORY_MMAP;for (i = 0; i < NB_BUFFER; i++) {v4l2_buf.index = i;if (ioctl(cam_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {perror("查询缓冲区失败");return -1;}pic.tmpbuffer[i] = mmap(NULL, v4l2_buf.length, PROT_READ, MAP_SHARED, cam_fd, v4l2_buf.m.offset);if (pic.tmpbuffer[i] == MAP_FAILED) {perror("映射缓冲区失败");return -1;}if (ioctl(cam_fd, VIDIOC_QBUF, &v4l2_buf) < 0) {perror("将缓冲区入队列失败");return -1;}}// 开启视频流int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (ioctl(cam_fd, VIDIOC_STREAMON, &type) < 0) {perror("启动捕获失败");return -1;}return 0;
}// 从摄像头抓取图像的函数
int v4l2Grab(void) {// 获取图像struct v4l2_buffer buff;buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buff.memory = V4L2_MEMORY_MMAP;if (ioctl(cam_fd, VIDIOC_DQBUF, &buff) < 0) {printf("从摄像头获取缓冲区失败\n");return -1;}pic.tmpbytesused[buff.index] = buff.bytesused;printf("大小 : %d\n", pic.tmpbytesused[buff.index]);// 查看部分YUV数据(调试用)unsigned char *yuv_data = pic.tmpbuffer[buff.index];printf("YUV数据示例: Y=%d, U=%d, V=%d\n", yuv_data[0], yuv_data[1], yuv_data[3]);// 保存图像int jpg_fd = open("v4l2.yuyv", O_RDWR | O_CREAT, 00700);if (jpg_fd == -1) {printf("打开文件失败!\n");return -1;}int writesize = write(jpg_fd, pic.tmpbuffer[buff.index], pic.tmpbytesused[buff.index]);printf("写入成功大小 : %d\n", writesize);close(jpg_fd);// 将缓冲区重新入队列if (ioctl(cam_fd, VIDIOC_QBUF, &buff) < 0) {printf("将缓冲区重新入队列失败");return -1;}return 0;
}// 关闭摄像头的函数
int v4l2_close(void) {// 解除内存映射struct v4l2_buffer v4l2_buf;v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;v4l2_buf.memory = V4L2_MEMORY_MMAP;for (int i = 0; i < NB_BUFFER; i++) {v4l2_buf.index = i;if (ioctl(cam_fd, VIDIOC_QUERYBUF, &v4l2_buf) == 0) {munmap(pic.tmpbuffer[i], v4l2_buf.length);}}close(cam_fd);return 0;
}// 辅助函数:限制数值范围
int CLAMP(int value, int min, int max) {if (value < min) return min;if (value > max) return max;return value;
}// 将YUV 422格式转换为RGB 24位格式的函数
int yuv422_rgb24(unsigned char *yuv_buf, unsigned char *rgb_buf, unsigned int width, unsigned int height) {unsigned int i, j;unsigned char y0, y1, u, v;unsigned char r, g, b;for (i = 0; i < height; i++) {for (j = 0; j < width; j += 2) {// 提取 YUV 组件y0 = yuv_buf[i * width * 2 + j * 2];   // 第一个像素的 Y 分量u  = yuv_buf[i * width * 2 + j * 2 + 1]; // U 是两个像素共享的y1 = yuv_buf[i * width * 2 + j * 2 + 2]; // 第二个像素的 Y 分量v  = yuv_buf[i * width * 2 + j * 2 + 3]; // V 是两个像素共享的// 转换第一个像素r = (int)(y0 + 1.402 * (v - 128));g = (int)(y0 - 0.344 * (u - 128) - 0.714 * (v - 128));b = (int)(y0 + 1.772 * (u - 128));// 限制并赋值到 RGB 缓冲区rgb_buf[(i * width + j) * 3 + 0] = (unsigned char)CLAMP(b, 0, 255);rgb_buf[(i * width + j) * 3 + 1] = (unsigned char)CLAMP(g, 0, 255);rgb_buf[(i * width + j) * 3 + 2] = (unsigned char)CLAMP(r, 0, 255);// 转换第二个像素,使用相同的 UV 值r = (int)(y1 + 1.402 * (v - 128));g = (int)(y1 - 0.344 * (u - 128) - 0.714 * (v - 128));b = (int)(y1 + 1.772 * (u - 128));// 限制并赋值到 RGB 缓冲区rgb_buf[(i * width + j + 1) * 3 + 0] = (unsigned char)CLAMP(b, 0, 255);rgb_buf[(i * width + j + 1) * 3 + 1] = (unsigned char)CLAMP(g, 0, 255);rgb_buf[(i * width + j + 1) * 3 + 2] = (unsigned char)CLAMP(r, 0, 255);}}return 0;
}// 将RGB数据写入PNG文件的函数
void write_data_to_png(const char *png_name, png_uint_32 width, png_uint_32 height, png_bytepp data, int color_type) {// 查看部分RGB数据(调试用)for (int i = 0; i < 10; i++) {pixel_RGB *pixel = &((pixel_RGB *)data)[i];printf("RGB数据示例: R=%d, G=%d, B=%d\n", pixel->red, pixel->green, pixel->blue);}FILE *fp = fopen(png_name, "wb");if (!fp) {perror("打开PNG文件用于写入出错");return;}png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);if (!png) {perror("创建PNG写入结构体出错");fclose(fp);return;}png_infop info = png_create_info_struct(png);if (!info) {perror("创建PNG信息结构体出错");png_destroy_write_struct(&png, NULL);fclose(fp);return;}png_init_io(png, fp);png_set_IHDR(png, info, width, height, 8, color_type, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);png_write_info(png, info);// 分配行指针png_bytep *row_pointers = malloc(height * sizeof(png_bytep));if (!row_pointers) {perror("分配行指针出错");png_destroy_write_struct(&png, &info);fclose(fp);return;}// 分配每行的内存for (unsigned int i = 0; i < height; ++i) {row_pointers[i] = (png_bytep)&(((pixel_RGB *)data)[i * width]);}png_write_image(png, row_pointers);png_write_end(png, NULL);png_destroy_write_struct(&png, &info);fclose(fp);free(row_pointers);
}// 设置客户端并发送PNG图像数据的函数
int client_setup_and_send(const char* server_ip) {// 初始化摄像头if (v4l2_init() == -1) {fprintf(stderr, "初始化摄像头失败.\n");return -1;}// 从摄像头抓取图像if (v4l2Grab() == -1) {fprintf(stderr, "从摄像头抓取图像失败.\n");v4l2_close();return -1;}// 分配RGB缓冲区unsigned char *rgb_buf = (unsigned char *)malloc(WIDTH * HEIGHT * 3);if (!rgb_buf) {fprintf(stderr, "分配RGB缓冲区失败.\n");v4l2_close();return -1;}// 将YUV数据转换为RGB数据yuv422_rgb24(pic.tmpbuffer[0], rgb_buf, WIDTH, HEIGHT);// 分配PNG图像数据typedef struct {unsigned char red;unsigned char green;unsigned char blue;} pixel_RGB;pixel_RGB *image_data_rgb = calloc(WIDTH * HEIGHT, sizeof(pixel_RGB));if (!image_data_rgb) {fprintf(stderr, "分配PNG图像数据失败.\n");free(rgb_buf);v4l2_close();return -1;}// 将RGB数据复制到PNG图像数据结构体中for (unsigned int i = 0; i < WIDTH * HEIGHT; i++) {image_data_rgb[i].red = rgb_buf[i * 3 + 2];image_data_rgb[i].green = rgb_buf[i * 3 + 1];image_data_rgb[i].blue = rgb_buf[i * 3 + 0];}// 保存为PNG图像const char *png_name = "camera_image.png";write_data_to_png(png_name, WIDTH, HEIGHT, (png_bytepp)image_data_rgb, PNG_COLOR_TYPE_RGB);// 创建套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror("创建套接字出错");free(rgb_buf);free(image_data_rgb);v4l2_close();return -1;}// 设置服务器地址和端口struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);server_addr.sin_addr.s_addr = inet_addr(server_ip);// 连接到服务器if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("连接到服务器出错");close(sockfd);free(rgb_buf);free(image_data_rgb);v4l2_close();return -1;}// 获取PNG图像数据大小FILE *png_file = fopen(png_name, "rb");if (!png_file) {perror("打开PNG文件出错");close(sockfd);free(rgb_buf);free(image_data_rgb);v4l2_close();return -1;}fseek(png_file, 0, SEEK_END);long png_data_size = ftell(png_file);fseek(png_file, 0, SEEK_SET);// 发送图像数据大小信息if (send(sockfd, &png_data_size, sizeof(png_data_size), 0) == -1) {perror("发送图像大小信息出错");fclose(png_file);close(sockfd);free(rgb_buf);free(image_data_rgb);v4l2_close();return -1;}// 发送图像数据char *png_data_buffer = (char *)malloc(png_data_size);if (!png_data_buffer) {perror("为发送PNG数据分配缓冲区出错");fclose(png_file);close(sockfd);free(rgb_buf);free(image_data_rgb);v4l2_close();return -1;}fread(png_data_buffer, 1, png_data_size, png_file);if (send(sockfd, png_data_buffer, png_data_size, 0) == -1) {perror("发送PNG数据出错");free(png_data_buffer);fclose(png_file);close(sockfd);free(rgb_buf);free(image_data_rgb);v4l2_close();return -1;}free(png_data_buffer);fclose(png_file);// 关闭套接字close(sockfd);// 释放资源free(rgb_buf);free(image_data_rgb);v4l2_close();return 0;
}// 客户端主函数
int main(int argc, char *argv[]) {if (argc!= 2) {fprintf(stderr, "用法: %s <服务器IP地址>\n", argv[0]);return -1;}const char* server_ip = argv[1];if (client_setup_and_send(server_ip) == -1) {fprintf(stderr, "客户端发送图像数据失败.\n");return -1;}return 0;
}
client.h
#ifndef CLIENT_H
#define CLIENT_H#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
//#include <time.h>
#include <linux/videodev2.h>
#include <png.h>#define CAM_DEV "/dev/video0"
#define WIDTH 640
#define HEIGHT 480
#define NB_BUFFER 4
#define PORT 8888// 用于存储图像数据的结构体
struct pic_data {unsigned char *tmpbuffer[NB_BUFFER];unsigned int tmpbytesused[NB_BUFFER];
} pic;typedef struct {unsigned char red;unsigned char green;unsigned char blue;
} pixel_RGB;// 函数原型声明
int v4l2_init(void);
int v4l2Grab(void);
int v4l2_close(void);
// 辅助函数:限制数值范围
int CLAMP(int value, int min, int max);
int yuv422_rgb24(unsigned char *yuv_buf, unsigned char *rgb_buf, unsigned int width, unsigned int height);
void write_data_to_png(const char *png_name, png_uint_32 width, png_uint_32 height, png_bytepp data, int color_type);
int client_setup_and_send();#endif

服务器

server.c
#include "server.h"// 处理单个客户端连接的函数
void handle_single_connection(int client_socket) {// 接收PNG图像数据的大小long png_data_size;if (recv(client_socket, &png_data_size, sizeof(png_data_size), 0) == -1) {perror("接收图像大小出错");close(client_socket);return;}// 接收PNG图像数据char *png_data_buffer = (char *)malloc(png_data_size);if (!png_data_buffer) {perror("为PNG数据分配缓冲区出错");close(client_socket);return;}long total_received = 0;while (total_received < png_data_size) {long received = recv(client_socket, png_data_buffer + total_received, png_data_size - total_received, 0);if (received == -1) {perror("接收PNG数据出错");free(png_data_buffer);close(client_socket);return;}total_received += received;}// 将接收到的数据保存为PNG文件const char *png_name = "received_image.png";FILE *fp = fopen(png_name, "wb");if (!fp) {perror("打开PNG文件用于写入出错");free(png_data_buffer);close(client_socket);return;}fwrite(png_data_buffer, 1, png_data_size, fp);fclose(fp);free(png_data_buffer);// 关闭客户端套接字close(client_socket);
}// 启动服务器并监听传入连接的函数
int start_server() {// 创建套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror("创建套接字出错");return -1;}// 绑定套接字到特定地址和端口struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);server_addr.sin_addr.s_addr = INADDR_ANY;if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("绑定套接字出错");close(sockfd);return -1;}// 监听传入连接if (listen(sockfd, 5) == -1) {perror("监听连接出错");close(sockfd);return -1;}return sockfd;
}// 服务器主函数,用于持续监听并处理客户端连接
int main() {int server_socket = start_server();if (server_socket == -1) {fprintf(stderr, "服务器启动失败.\n");return -1;}while (1) {// 接受客户端连接struct sockaddr_in client_addr;socklen_t client_addr_len = sizeof(client_addr);int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);if (client_socket == -1) {perror("接受客户端连接出错");continue;}// 处理客户端连接handle_single_connection(client_socket);}// 关闭服务器套接字(实际上这里不会执行到,因为循环一直运行)close(server_socket);return 0;
}
server.h
#ifndef SERVER_H
#define SERVER_H#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <png.h>#define BUFFER_SIZE 1024
#define PORT 8888// 函数原型声明
int start_server();
void handle_connection(int client_socket);#endif

Makefile

CC = gcc
CFLAGS = -Wall --std=gnu99 -I/usr/src/linux-headers-3.2.0-23-generic-pae/include -Wno-cpp
LDFLAGS = -L/usr/lib/i386-linux-gnu

all: server client

server: server.c server.h
    $(CC) $(CFLAGS) $(LDFLAGS) -o server server.c -lpng

client: client.c client.h
    $(CC) $(CFLAGS) $(LDFLAGS) -o client client.c -lpng
clean:
    rm -f server client

这两个要换成自己的路径:

  • CFLAGS = -Wall --std=gnu99 -I/usr/src/linux-headers-3.2.0-23-generic-pae/include -Wno-cpp
  • LDFLAGS = -L/usr/lib/i386-linux-gnu

相关文章:

Linux-Ubuntu16.04摄像头 客户端抓取帧并保存为PNG

1.0&#xff1a;client.c抓取帧并保存为PNG #include <stdio.h> // 标准输入输出库 #include <stdlib.h> // 标准库&#xff0c;包含内存分配等函数 #include <string.h> // 字符串操作库 #include <linux/videodev2.h> // V4L2 视频设备…...

手机ip地址取决于什么?可以随便改吗

手机IP地址是指手机在连接到互联网时所获得的唯一网络地址&#xff0c;这个地址由一串数字组成&#xff0c;用于在网络中标识和定位设备。每个设备在连接到网络时都会被分配一个IP地址&#xff0c;它可以帮助数据包在网络中准确地找到目标设备。那么&#xff0c;手机IP地址究竟…...

计算机网络:TCP/IP协议的五大重要特性介绍

目录 一、逻辑编址 二、路由选择 三、名称解析 四、错误控制和流量控制 五、多应用支持 今天给大家聊聊TCP/IP协议中五大重要特性相关的知识,希望对大家深入了解该协议提供一些帮助! 一、逻辑编址 首先要了解什么是物理地址、逻辑地址。 ●...

Java与AWS S3的文件操作

从零开始&#xff1a;Java与AWS S3的文件操作 一、什么是 AWS S3&#xff1f;AWS S3 的特点AWS S3 的应用场景 二、Java整合S3方法使用 MinIO 客户端操作 S3使用 AWS SDK 操作 S3 &#xff08;推荐使用&#xff09; 三、总结 一、什么是 AWS S3&#xff1f; Amazon Simple Sto…...

详解 YOLOv5 模型运行参数含义以及设置及在 PyCharm 中的配置方法

详解 YOLOv5 模型运行参数含义以及设置及在 PyCharm 中的配置方法 这段代码中使用的命令行参数允许用户在运行 YOLOv5 模型时自定义多种行为和设置。以下是各个参数的详细说明和使用示例&#xff0c;以及如何在 PyCharm 中设置这些参数以确保正确运行带有参数的脚本。 命令行…...

Vue根据Div内容的高度给其Div设置style height

在 Vue.js 中&#xff0c;你可以使用 JavaScript 来动态地根据 div 的内容高度来设置其 style 的 height 属性。这通常是在组件挂载或更新时完成的&#xff0c;因为这时你已经有了实际的 DOM 元素可以操作。 以下是一个简单的例子&#xff0c;展示了如何实现这一点&#xff1a…...

驱动篇的开端

准备 在做之后的动作前&#xff0c;因为win7及其以上的版本默认是不支持DbgPrint&#xff08;大家暂时理解为内核版的printf&#xff09;的打印&#xff0c;所以&#xff0c;为了方便我们的调试&#xff0c;我们先要修改一下注册表 创建一个reg文件然后运行 Windows Registr…...

OpenSSL 自建CA 以及颁发证书(网站部署https双向认证)

前言 1、前面写过一篇 阿里云免费ssl证书申请与部署&#xff0c;大家可以去看下 一、openssl 安装说明 1、这部分就不再说了&#xff0c;我使用centos7.9&#xff0c;是自带 openssl的&#xff0c;window的话&#xff0c;要去下载安装 二、CA机构 CA机构&#xff0c;全称为…...

吾杯网络安全技能大赛WP(部分)

吾杯网络安全技能大赛WP(部分) MISC Sign 直接16进制解码即可 原神启动 将图片用StegSolve打开 找到了压缩包密码 将解出docx文件改为zip 找到了一张图片和zip 再把图片放到stegSlove里找到了img压缩包的密码 然后在document.xml里找到了text.zip压缩包密码 然后就出来fl…...

按vue组件实例类型实现非侵入式国际化多语言翻译

#vue3##国际化##本地化##international# web界面国际化&#xff0c;I18N&#xff08;Internationalization&#xff0c;国际化&#xff09;&#xff0c;I11L(International&#xff0c;英特纳雄耐尔)&#xff0c;L10N&#xff08;Localization&#xff0c;本地化&#xff09;&…...

Java入门:22.集合的特点,List,Set和Map集合的使用

1 什么是集合 本质就是容器的封装&#xff0c;可以存储多个元素 数组一旦创建&#xff0c;长度就不能再改变了。 数组一旦创建&#xff0c;存储内容的类型不能改变。 数组可以存储基本类型&#xff0c;也可以存储引用类型。 数组可以通过length获得容量的大小&#xff0c;但…...

重生之我在异世界学编程之C语言:深入指针篇(下)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 目录 题集&#xff08;1&#xff09;指针笔试题1&a…...

理解Parquet文件和Arrow格式:从Hugging Face数据集的角度出发

parquet发音&#xff1a;美 [pɑrˈkeɪ] 镶木地板&#xff1b;拼花木地板 理解Parquet文件和Arrow格式&#xff1a;从Hugging Face数据集的角度出发 引言 在机器学习和大数据处理中&#xff0c;数据的存储和传输格式对于性能至关重要。两种广泛使用的格式是 Parquet 和 Arr…...

下载 M3U8 格式的视频

要下载 M3U8 格式的视频&#xff08;通常是 HLS 视频流&#xff09;&#xff0c;可以尝试以下几种方法&#xff1a; 方法 1&#xff1a;使用下载工具&#xff08;推荐&#xff09; 1. IDM&#xff08;Internet Download Manager&#xff09;&#xff1a; 安装 IDM 并启用浏…...

Tomcat使用教程

下载地址&#xff1a;https://tomcat.apache.org/ 配置环境变量 变量名: CATALINA_HOME 变量值: D:\tools\apache-tomcat-9.0.97 Path: %CATALINA_HOME%\bin 启动Tomcat(打开命令提示符) startup.bat 解决乱码问题(打开conf\logging.properties) java.util.logging.Conso…...

LabVIEW氢气纯化控制系统

基于LabVIEW的氢气纯化控制系统满足氢气纯化过程中对精确控制的需求&#xff0c;具备参数设置、过程监控、数据记录和报警功能&#xff0c;体现了LabVIEW在复杂工业控制系统中的应用效能。 项目背景 在众多行业中&#xff0c;尤其是石油化工和航天航空领域&#xff0c;氢气作为…...

现在的电商风口已经很明显了

随着电商行业的不断发展&#xff0c;直播带货的热潮似乎正逐渐降温&#xff0c;而货架电商正成为新的焦点。抖音等平台越来越重视货架电商&#xff0c;强调搜索功能的重要性&#xff0c;预示着未来的电商中心将转向货架和搜索。 在这一转型期&#xff0c;AI技术与电商的结合为…...

Uniapp触底刷新

在你的代码中&#xff0c;使用了 scroll-view 来实现一个可滚动的评论区域&#xff0c;并且通过监听 scrolltolower 事件来触发 handleScrollToLower 函数&#xff0c;以实现“触底更新”或加载更多评论的功能。 关键部分分析&#xff1a; scroll-view 组件: scroll-view 是一…...

开源项目 - face parsing 人脸区域分割 人像区域分割 人脸分割 人像区域分割 BiSeNet

开源项目 - face parsing 人脸区域分割 人像区域分割 人脸分割 人像区域分割 BiSeNet 项目地址&#xff1a;GitHub - XIAN-HHappy/face_parsing: face_parsing 脸部分割 示例&#xff1a; ​​​​ 助力快速掌握数据集的信息和使用方式。 数据可以如此美好&#xff01;...

python游戏设计---飞机大战

1.前言 上次做飞机大战游戏有人这么说&#xff1a; 好好好&#xff01;今天必须整一个&#xff0c;今天我们来详细讲解一下&#xff0c;底部找素材文件下载&#xff01;&#xff01;&#xff01; 2.游戏制作 目录如下&#xff1a; 1.导入的包 import pygame import sys imp…...

13TB的StarRocks大数据库迁移过程

公司有一套StarRocks的大数据库在大股东的腾讯云环境中&#xff0c;通过腾讯云的对等连接打通&#xff0c;通过dolphinscheduler调度datax离线抽取数据和SQL计算汇总&#xff0c;还有在大股东的特有的Flink集群环境&#xff0c;该环境开发了flink开发程序包部署&#xff0c;实时…...

HTTP代理有那些常见的安全协议?

在数据采集领域&#xff0c;HTTP代理扮演着至关重要的角色&#xff0c;它不仅帮助我们访问互联网资源&#xff0c;还涉及到数据的安全传输。了解HTTP代理中常见的安全协议对于保护数据安全、提高数据采集效率至关重要。那么&#xff0c;有哪些安全协议是在HTTP代理中常用的呢&a…...

Kylin Server V10 下基于Kraft模式搭建Kafka集群

一、Kraft 模式与 ZooKeeper 模式简介 在Kafka 2.8 之前,Kafka 重度依赖 ZooKeeper 集群做元数据管理、Controller 的选举等(统称为共识服务);当ZooKeeper 集群性能发生抖动时,Kafka 的性能也会受到很大的影响。如下图所示: 在 Kafka 2.8 之后,引入了基于 Raft …...

tauri使用github action打包编译多个平台arm架构和inter架构包踩坑记录

这些error的坑&#xff0c;肯定是很多人不想看到的&#xff0c;我的开源软件PakePlus是使用tauri开发的&#xff0c;PakePlus是一个界面化将任何网站打包为轻量级跨平台软件的程序&#xff0c;利用Tauri轻松构建轻量级多端桌面应用和多端手机应用&#xff0c;为了实现发布的时候…...

Python爬虫与窗口实现翻译小工具(仅限学习交流)

Python爬虫与窗口实现翻译小工具(仅限学习交流) 在工作中,遇到一个不懂的单词时,就会去网页找对应的翻译,我们可以用Python爬虫与窗口配合,制作一个简易的翻译小工具,不需要打开网页,自动把翻译结果显示出来。 整个过程比较简单。 # This is a sample Python script. …...

紫光展锐联合上汽海外发布量产车型,赋能汽车智能化

当前&#xff0c;智能汽车产业迎来重大变局&#xff0c;随着人工智能、5G、大数据等新一代信息技术的迅猛发展&#xff0c;智能网联汽车正呈现强劲发展势头。 11月26日&#xff0c;在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上&#xff0c;紫光展锐与上汽海外出行联合发…...

Maven 打包出现问题解决方案

我执行 mvn install 报如下错误 可是我在 web 模块中能正确引用到 common 的类&#xff0c;于是我把 web 引用到的 common 中的类先移动到 web 模块中&#xff0c;然后把 common 模块的类都删掉&#xff0c;然后再次执行 mvn install,结果报错如下&#xff1a; [ERROR] Faile…...

第四话:JS中的eval函数

theme: channing-cyan 1.不要使用eval&#xff01; 如果你从来都没有用到过eval这个函数&#xff0c;甚至你都不知道这个函数的作用。那么我只能说&#xff1a;你做了一件正确的事情 o.O 虽然我这篇文章要说一下eval函数的一些能力和注意点&#xff0c;但是我希望&#xff0…...

歇一歇,写写段子

无聊的日子都在写段子1.0 中学的时候喜欢看意林之类的杂志&#xff0c; 里面的作者用乱七八糟的理由跑去旅游&#xff0c;然后说“阻碍你脚步的永远只有逃离的勇气和对生活的热爱”&#xff0c; 我觉得太对了&#xff0c;可惜 12306 付款方式里没有勇气和热爱&#xff0c;不…...

TypeScript (一)运行环境配置,数据类型,可选类型,联合类型,type与interface,交叉类型,断言as,字面量类型,类型缩小

文章目录 一、认识TS1.1 JS 存在的问题1.2 TS的出现1.3 TS运行环境运行ts的三种方式 1.4 变量声明1.5 类型推断 二、数据类型2.1 JS数据类型(1) 数组Array(2) 对象Object(3) 其他类型 2.2 TS特有数据类型(1) any类型(2) unknown类型(3) void类型(4) never (了解)(5) tuple类型 …...