linux学习:多媒体开发库SDL+视频、音频、事件子系统+处理yuv视频源

news2024/11/20 9:22:49

目录

编译和移植

视频子系统

视频子系统产生图像的步骤

api

初始化 SDL 的相关子系统

使用指定的宽、高和色深来创建一个视窗 surface

使用 fmt 指定的格式创建一个像素点​编辑

将 dst 上的矩形 dstrect 填充为单色 color​编辑

将 src 快速叠加到 dst 上​编辑

更新 screen 上的图像元素​编辑

api例子

音频子系统

SDL 中默认支持的对 wav 格式 的音频文件的 API

存放音频数据的具体信息

加载 wav 格式的音频文件​编辑

启动音频设备​编辑

暂停或者继续​编辑

api例子

事件子系统

联合体

使用鼠标的实例

处理YUV视频源


sdl是一个跨平台的底层开发库,提供操作诸如音频、 键盘、鼠标、游戏杆以及显卡等硬件的方法,被很多多媒体播放器、模拟器和流行游戏所使 用,SDL 支持 Windows、MacOS、Linux、iOS 以及 Android,也就是说你目所能及的 几乎所有平台它都能运行,并且 SDL 是开源的,完全由 C 语言编写,

编译和移植

  1. 下载:http://www.libsdl.org/release/SDL-1.2.15.tar.gz
  2. 解压进入根目录
  3. ./configure --host=arm-none-Linux-gnueabi --prefix=/usr/local/sdl
    1. 注意,--host 是指定交叉编译器的前缀,--prefix 是指定 SDL 的安装目录,两者都要根 据你的具体情况来写,不必照抄
  4. make
  5. make install
  6. 将编译后的目录/usr/local/sdl 全部拷贝到开发板中,设置好库目录的环境变量
    1. 将此目录拷贝到开发板的/usr/local/sdl 中就设置export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/sdl/lib

视频子系统

在屏幕的显示能力,当我们需要显示图片、文字的时候,那就必须使用视频子系统

支持设置视频模式,即创建视频窗口,也支持直接的图像帧缓冲、 支持 Alpha 像素混合、支持窗口管理和图形渲染等

视频子系统产生图像的步骤

  • 初始化 SDL 视频子系统
  • 设置视频模式(包括宽高、色深等),并创建得到视窗 surface
  • 加载一张图像,获得该图像的 surface
  • 将图像 surface“放到”视窗 surface 上,同时可以设置你要放置的位置
  • 更新视窗 surface,使得图像可

api

初始化 SDL 的相关子系统

使用指定的宽、高和色深来创建一个视窗 surface

使用 fmt 指定的格式创建一个像素点

将 dst 上的矩形 dstrect 填充为单色 color

将 src 快速叠加到 dst 上

更新 screen 上的图像元素

api例子

使用以上 API,结合触摸屏运行库 tslib 来实现移动图片的效果

// 初始化 SDL 视频子系统,并设置视窗 surface 的参数(与 LCD 一致)
SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(LCD_WIDTH, LCD_HEIGHT, 0, SDL_ANYFORMAT | SDL_SWSURFACE);

// 装载 BMP 图片文件 SDL 表示没压力
image = SDL_LoadBMP(argv[1]);

// 1, image_offset 规定了图片要显示的矩形部分
// 2, background_offset 规定了图像要显示在视窗的那个位置,其中:
SDL_Rect image_offset;
SDL_Rect backgroud_offset;
bzero(&image_offset, sizeof(image_offset));
bzero(&backgroud_offset, sizeof(backgroud_offset));
printf("press Ctrl+c to quit.\n");
sem_init(&s, 0, 0);

pthread_t tid;
pthread_create(&tid, NULL, read_moving, NULL);

// 1, x 和 y 规定了图像要显示的矩形的左上角坐标
// 2, w 和 h 规定了以(x,y)为左上角的矩形的宽和高
image_offset.x = 0;
image_offset.y = 0;
image_offset.w = 400;
image_offset.h = 240;

while (1) {
    // 产生一个 RGB 值为 000(黑色)的像素
    uint32_t black_pixel = SDL_MapRGB(screen->format, 0, 0, 0);
    // 将屏幕刷成黑色
    SDL_FillRect(screen, &screen->clip_rect, black_pixel);
    // 将图像(image)blit 到屏幕上(screen)
    long tmp1 = backgroud_offset.x;
    long tmp2 = backgroud_offset.y;
    SDL_BlitSurface(image, &image_offset, screen, &backgr_offset);

    // 显示 screen 上的元素
    SDL_Flip(screen);

    // 1,x 和 y 规定了图像 surface 放在视窗的左上角坐标
    // 2,w 和 h 都是作废的。
    backgroud_offset.x = tmp1 + xoffset;
    backgroud_offset.y = tmp2 + yoffset;

    printf("backgroud_offset.x: %d\n", backgroud_offset.x);
    printf("backgroud_offset.y: %d\n", backgroud_offset.y);

    sem_wait(&s);
}
  • 要渲染视频流需要结合 FFmpeg 来做

  • 图片不是 bmp 格式的,比如 jpeg、png、tiff 等,需要使用第三方扩展库 SDL_image

音频子系统

SDL 中默认支持的对 wav 格式 的音频文件的 API

存放音频数据的具体信息

加载 wav 格式的音频文件

启动音频设备

暂停或者继续

api例子

#include <stdio.h>
#include <stdlib.h>
#include "SDL.h"
#include "SDL_audio.h"
#include "SDL_config.h"

struct wave
{
    SDL_AudioSpec spec;
    Uint8 *sound; /* 音频数据缓冲区指针 */
    Uint32 soundlen; /* 音频数据尺寸 */
    int soundpos; /* 已处理数据大小 */
} wave;

// 画进度条
void draw_progress_bar(int left, int len)
{
    int i;
    for (i = 0; i < 20; i++)
        printf("\b");
    printf("[");
    int n = ((1 - (float)left / len) * 100) / 10;
    for (i = 0; i <= n; i++)
        printf("-");
    printf(">");
    for (i = 0; i < 9 - n; i++)
        printf(" ");
    printf("] %.1f%%", (1 - (float)left / len) * 100);
    fflush(stdout);
}

// 音频解码回调函数
void deal_audio(void *unused, Uint8 *stream, int len)
{
    Uint8 *waveptr;
    int waveleft;

    waveptr = wave.sound + wave.soundpos;
    waveleft = wave.soundlen - wave.soundpos;

    while (waveleft <= len)
    {
        memcpy(stream, waveptr, waveleft);
        stream += waveleft;
        len -= waveleft;
        waveptr = wave.sound;
        waveleft = wave.soundlen;
        wave.soundpos = 0;

        printf("\n");
        SDL_CloseAudio();
        SDL_FreeWAV(wave.sound);
        SDL_Quit();

        exit(0);
    }
    memcpy(stream, waveptr, len);
    wave.soundpos += len;

    draw_progress_bar(waveleft, wave.soundlen);
}

int main(int argc, char *argv[])
{
    // 初始化音频子系统
    SDL_Init(SDL_INIT_AUDIO);

    // 加载 WAV 文件
    SDL_LoadWAV(argv[1], &wave.spec, &wave.sound, &wave.soundlen);

    // 指定音频数据处理回调函数
    wave.spec.callback = deal_audio;

    // 启动音频设备
    SDL_OpenAudio(&wave.spec, NULL);
    SDL_PauseAudio(0);

    printf("\npress Enter to pause and unpause.\n");
    static int pause_on = 1;
    while (1)
    {
        // 按下回车键,暂停或播放
        getchar();
        SDL_PauseAudio(pause_on++);

        if (!(pause_on %= 2))
            printf("stopped.\n");
    }

    return 0;
}

SDL 利用函数 SDL_LoadWAV()将音频数据加载到一个缓冲区中,然后 通过结构体 SDL_AudioSpec 中的 callback 指定回调函数 deal_audio(),该函数会在音 频设备准备好要读取数据的时候被自动调用。 然后,调用 SDL_OpenAudio()启动音频设备,并且调用 SDL_PauseAudio(0)来使 得启动整个流程,此时只要音频设备准备好了,需要数据的时候,就会自动调用 deal_audio 这个函数。回调函数 deal_audio()就像一个搬运工,一旦音频设备准备好可以读取数据了, 他就将音频数据源源不断地搬到音频设备上去播放

音频文件不是 wav 格式的,比如 MP3,MIDI,OGG,MOD 这些,就需要用到 SDL 的第三方扩展库 SDL_Mixer。

事件子系统

  • SDL的事件允许程序接收从用户输入的信息,当调用SDL_Init(SDL_INIT_VIDEO)初始化视频子系统时,事件子系统将被连带自动初始化。
  • 本质上所有的事件都将被SDL置入一个所谓的“等待队列”中,我们可以使用诸如SDL_PollEvent()或者 SDL_WaitEvent()或者 SDL_PeepEvent()来处理或者检查当前正在等待的事件。
  • SDL中处理事件的关键核心,是一个叫SDL_Event的联合体,事实上“等待队列”中储存的就是这些联合体,SDL_PollEvent()或者SDL_WaitEvent()讲这些联合体从队列中读出,然后根据其中的信息作出相应的处理

联合体

囊括了SDL-1.2版本所支持的所有事件

  • type事件的类型
  • active事件触发
  • key键盘
  • motion鼠标移动
  • button鼠标按键
  • jaxis游戏杆摇杆
  • jball游戏杆轨迹球
  • jhatJoystick游戏杆帽
  • jbutton游戏杆按键
  • resize窗口大小变更
  • expose窗口焦点变更
  • quit退出
  • user用户自定义事件
  • syswm未定义窗口管理事件

使用鼠标的实例

功能

  • 使用鼠标左键点击向左小箭头,显示上一张图片
  • 使用鼠标左键点击向右小箭头,显示下一张图片
  • 使用鼠标右键退出程序

代码

#include <SDL.h>
#include <stdio.h>
#include <stdbool.h>

#define WIDTH 800
#define HEIGHT 480
#define BPP 32

SDL_Surface* screen;
SDL_Surface* image;
SDL_Surface* left, *right;

SDL_Surface* load_image(const char* filename) {
    return SDL_DisplayFormat(SDL_LoadBMP(filename));
}

void show_bmp(const char* filename) {
    // Fill the screen with black color
    uint32_t black_pixel = SDL_MapRGB(screen->format, 0, 0, 0);
    SDL_FillRect(screen, &screen->clip_rect, black_pixel);

    // Load the image
    image = load_image(filename);

    // Set the position of the image
    static SDL_Rect rect = {0, 0};
    SDL_BlitSurface(image, NULL, screen, &rect);

    // Set the positions of the left and right arrows
    static SDL_Rect left_pos = {100, 200};
    static SDL_Rect right_pos = {700, 200};
    SDL_BlitSurface(left, NULL, screen, &left_pos);
    SDL_BlitSurface(right, NULL, screen, &right_pos);

    // Refresh the screen to display the image
    SDL_Flip(screen);
}

int main(int argc, char const* argv[]) {
    if (argc != 2) {
        printf("Usage: %s <bmp_directories>\n", argv[0]);
        exit(0);
    }

    SDL_Init(SDL_INIT_EVERYTHING);

    screen = SDL_SetVideoMode(WIDTH, HEIGHT, BPP, SDL_SWSURFACE);

    const char* bmp_files[] = {"1.bmp", "2.bmp", "3.bmp", "4.bmp"};
    chdir(argv[1]);
    left = load_image("left.bmp");
    right = load_image("right.bmp");

    // Blit the image onto the screen
    SDL_Rect rect = {0, 0};
    SDL_BlitSurface(image, NULL, screen, &rect);

    SDL_Rect left_pos = {100, 200};
    SDL_Rect right_pos = {700, 200};

    // Set white color as transparent
    int32_t key = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
    SDL_SetColorKey(left, SDL_SRCCOLORKEY, key);
    SDL_SetColorKey(right, SDL_SRCCOLORKEY, key);

    // Display the first image
    show_bmp(bmp_files[0]);

    // Block and wait for mouse click
    int i = 0;
    SDL_Event event;
    while (1) {
        SDL_WaitEvent(&event);

        // Switch to the previous image when the left arrow is clicked
        if (event.button.type == SDL_MOUSEBUTTONUP &&
            event.button.button == SDL_BUTTON_LEFT &&
            event.button.y >= 200 &&
            event.button.y <= 287) {
            if (event.button.x >= 100 && event.button.x <= 160) {
                i = (i == 0) ? 3 : (i - 1);
            }
            if (event.button.x >= 700 && event.button.x <= 760) {
                i = (i + 1) % 4;
            }
            // Release the current image resources before displaying another image
            SDL_FreeSurface(image);
            show_bmp(bmp_files[i]);
        }

        // Quit the program when the right mouse button is clicked
        if (event.button.type == SDL_MOUSEBUTTONUP &&
            event.button.button == SDL_BUTTON_RIGHT) {
            break;
        }
    }

    return 0;
}

处理YUV视频源

使用V4L2接口获取摄像头数据(YUV格式),然后使用SDL将视频数据显示到LCD显示器上

步骤

  • 1.准备好LCD,设置好相应的参数,备用
  • 2.准备好摄像头,设置好采集格式等参数,备用
  • 3.初始化SDL,并创建YUV层,备用
  • 4.启动摄像头,开始捕获YUV数据,并将数据丢给SDL的YUV处理层显示

具体代码

  • 1
    • 打开LCD设备
    • 获取LCD显示器的设备参数
    • 申请一块适当跟LCD尺寸一样大小的显存
  • 2.
    • 打开摄像头设备文件
    • 配置摄像头的采集格式
    • 设置即将要申请的摄像头缓存的参数
    • 使用该参数reqbuf来申请缓存
    • 根据刚刚设置的reqbuf.count的值,来定义相应数量的struct v4l2_buffer
  • 3.
    • 初始化带音视频和定时器子系统的SDL
    • 创建基本surface
    • 创建一个YUYV格式的surface
  • 4.
    • 启动摄像头
    • 准备好应用层缓冲区参数
    • 开始捕获采集数据
    • 将数据丢给SDL处理
#include <SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <linux/videodev2.h>

#define LCD_WIDTH 800
#define LCD_HEIGHT 480

void 打开LCD并分配显存(unsigned int **fb_mem, struct fb_var_screeninfo *lcdinfo) {
    int lcd = open("/dev/fb0", O_RDWR);
    ioctl(lcd, FBIOGET_VSCREENINFO, lcdinfo);
    *fb_mem = mmap(NULL, lcdinfo->xres * lcdinfo->yres * lcdinfo->bits_per_pixel / 8,
                   PROT_READ | PROT_WRITE, MAP_SHARED, lcd, 0);
}

void 打开摄像头并配置(int *cam_fd, struct v4l2_format *fmt, int *nbuf, struct v4l2_requestbuffers *reqbuf,
                   struct v4l2_buffer *buffer, unsigned char **start) {
    *cam_fd = open("/dev/video3", O_RDWR);
    bzero(fmt, sizeof(*fmt));
    fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt->fmt.pix.width = LCD_WIDTH;
    fmt->fmt.pix.height = LCD_HEIGHT;
    fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; // YUYV 格式
    fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
    ioctl(*cam_fd, VIDIOC_S_FMT, fmt);
    
    *nbuf = 3;
    bzero(reqbuf, sizeof(*reqbuf));
    reqbuf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf->memory = V4L2_MEMORY_MMAP;
    reqbuf->count = *nbuf;
    ioctl(*cam_fd, VIDIOC_REQBUFS, reqbuf);

    for (int i = 0; i < *nbuf; i++) {
        bzero(&buffer[i], sizeof(buffer[i]));
        buffer[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buffer[i].memory = V4L2_MEMORY_MMAP;
        buffer[i].index = i;
        ioctl(*cam_fd, VIDIOC_QUERYBUF, &buffer[i]);
        start[i] = mmap(NULL, buffer[i].length, PROT_READ | PROT_WRITE,
                        MAP_SHARED, *cam_fd, buffer[i].m.offset);
        ioctl(*cam_fd, VIDIOC_QBUF, &buffer[i]);
    }
}

int main() {
    int lcd, cam_fd, nbuf;
    unsigned int *fb_mem;
    struct fb_var_screeninfo lcdinfo;
    struct v4l2_format fmt;
    struct v4l2_requestbuffers reqbuf;
    struct v4l2_buffer buffer[3];
    unsigned char *start[3];

    // 打开 LCD 并分配帧缓冲区
    打开LCD并分配显存(&fb_mem, &lcdinfo);

    // 打开摄像头并配置
    打开摄像头并配置(&cam_fd, &fmt, &nbuf, &reqbuf, buffer, start);

    // 初始化 SDL 包括视频、音频和定时器子系统
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);

    // 创建基本表面
    SDL_Surface *screen = NULL;
    screen = SDL_SetVideoMode(LCD_WIDTH, LCD_HEIGHT, 0, 0);

    // 创建 YUYV 格式的表面
    SDL_Overlay *bmp = SDL_CreateYUVOverlay(fmt.fmt.pix.width, fmt.fmt.pix.height,
                                             SDL_YUY2_OVERLAY, screen);

    // 启动摄像头
    enum v4l2_buf_type vtype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(cam_fd, VIDIOC_STREAMON, &vtype);

    // 准备应用层缓冲区参数
    struct v4l2_buffer v4lbuf;
    bzero(&v4lbuf, sizeof(v4lbuf));
    v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    v4lbuf.memory = V4L2_MEMORY_MMAP;

    while (1) {
        // 捕获数据
        for (int i = 0; i < nbuf; i++) {
            v4lbuf.index = i;
            ioctl(cam_fd, VIDIOC_DQBUF, &v4lbuf);
            memcpy(bmp->pixels[0], start[i], buffer[i].length);
            bmp->pitches[0] = fmt.fmt.pix.width;
            ioctl(cam_fd, VIDIOC_QBUF, &v4lbuf);
        }

        // 锁定 YUV 重叠
        SDL_LockYUVOverlay(bmp);
        // 解锁 YUV 重叠
        SDL_UnlockYUVOverlay(bmp);
        // 显示 YUV 重叠
        SDL_DisplayYUVOverlay(bmp, NULL);
    }

    // 清理
    munmap(fb_mem, lcdinfo.xres * lcdinfo.yres * lcdinfo.bits_per_pixel / 8);
    close(lcd);
    close(cam_fd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1675204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringAMQP Work Queue 工作队列

消息模型: 代码模拟: 相较于之前的基础队列&#xff0c;该队列新增了消费者 不再是一个&#xff0c;所以我们通过代码模拟出两个consumer消费者。在原来的消费者类里写两个方法 其中消费者1效率高 消费者2效率低 RabbitListener(queues "simple.queue")public voi…

经典文献阅读之--U-BEV(基于高度感知的鸟瞰图分割和神经地图的重定位)

0. 简介 高效的重定位对于GPS信号不佳或基于传感器的定位失败的智能车辆至关重要。最近&#xff0c;Bird’s-Eye-View (BEV) 分割的进展使得能够准确地估计局部场景的外观&#xff0c;从而有利于车辆的重定位。然而&#xff0c;BEV方法的一个缺点是利用几何约束需要大量的计算…

React useEffect Hook: 理解和解决组件双重渲染问题

在React中&#xff0c;useEffect可能会在组件的每次渲染后运行&#xff0c;这取决于它的依赖项。如果你发现useEffect运行了两次&#xff0c;并且你正在使用React 18或更高版本的严格模式&#xff08;Strict Mode&#xff09;&#xff0c;这可能是因为在开发模式下&#xff0c;…

解锁楼宇自动化新维度西门子Insight+BACnet IP I/O控制器

数字城市的楼宇自动化已不再是一个遥不可及的概念&#xff0c;而是成为了现代建筑的标配。特别是在大型商业综合体、高端写字楼和公共设施中&#xff0c;高效的楼宇管理系统是确保环境舒适度与能源效率的关键。当提及楼宇自动化领域的佼佼者&#xff0c;西门子Insight楼宇自动化…

Spring WebFlux:响应式编程

在软件开发领域&#xff0c;随着互联网应用的规模和复杂性不断增加&#xff0c;传统的编程模型逐渐暴露出一些局限性&#xff0c;尤其是在面对高并发、大规模数据流处理等场景时。为了应对这些挑战&#xff0c;响应式编程&#xff08;Reactive Programming&#xff09;应运而生…

AuroraFOC使用指南一(STM32F405双路FOC)

一. 简介 哈喽&#xff0c;感谢各位选择AuroraFOC开发板&#xff0c;在这里将对其进行一个详细的介绍&#xff0c;方便大家使用。并且对提供的工程文件和上位机的操作也进行了详细的说明。 有什么疑问或者好的建议 可以微信联系: WU1356742146 最后再次感谢大家的支持。 Aur…

Transformers中加载预训练模型的过程剖析(一)

使用HuggingFace的Transformers库加载预训练模型来处理下游深度学习任务很是方便,然而加载预训练模型的方法多种多样且过程比较隐蔽,这在一定程度上会给人带来困惑。因此,本篇文章主要讲一下使用不同方法加载本地预训练模型的区别、加载预训练模型及其配置的过程,藉此做个记…

PostgreSQL 用户及授权管理 04:授予及回收权限

PostgreSQL 是一个坚如磐石的数据库&#xff0c;它非常注重安全性&#xff0c;提供了非常丰富的基础设施来处理权限、特权和安全策略。在前面的章节中以我们介绍的基本概念为基础&#xff0c;重新审视角色概念&#xff0c;特别关注授予角色的安全性和权限&#xff08;角色可以是…

Linux/ubuntu build编译make时出现has modification time int the future的问题解决方法

针对Linux由于双系统之间的时间冲突导致linux时间经常变化&#xff0c;出现执行make命令时出现“make[2]: Warning: File xxx.c’ has modification time 1.6e05 s in the future “警告的问题&#xff0c;亦或者虚拟机出现相同的问题。 由于时钟同步问题&#xff0c;出现 warn…

CAST: Cross-Attention in Space and Time for Video Action Recognition

标题&#xff1a;CAST: 时空交叉注意力网络用于视频动作识别 原文链接&#xff1a;2311.18825v1 (arxiv.org)https://arxiv.org/pdf/2311.18825v1 源码链接&#xff1a;GitHub - KHU-VLL/CASThttps://github.com/KHU-VLL/CAST 发表&#xff1a;NeurIPS-2023&#xff08;CCF A…

SwiftUI 调整视图内容周围间隙(Content Margins)的“时髦”方法

概述 在 SwiftUI 开发的应用中,往往在小屏设备(比如 iPhone)上布局良好的 App 放到大屏(iPad)上后就会“一塌糊涂”。因为它们一味的只想着“占据”却不知道“舍弃”。 从 iOS 17.0(iPad 17.0)开始苹果提供了原生的视图修改器方法专注于处理此事。 在本篇博文中,您将…

MVC WebAPI

创建项目 创建api控制器 》》》 web api 控制器要继承 ApiController 》》》 数据会自动装配 及自动绑定 》》》》FromBody&#xff1a; Post请求的基础类型的参数和Get请求有点不一样&#xff0c;我们知道Get请求的参数是通过Url来传递的&#xff0c;而Post请求则是通过H…

华为涅槃,余承东重生

最近一段时间&#xff0c;余承东甚为低调。最为明显的是&#xff0c;“遥遥领先”已经听不到了&#xff0c;“余大嘴”口中的措辞越来越克制。 今后手机相关的发布会&#xff0c;或许不再看到余承东的身影。 5月10日&#xff0c;余承东的职位正式更新&#xff0c;从终端BG CE…

暴雨分布式存储集群助重庆高校打造智慧校园

教育是国家发展的基石&#xff0c;教育兴则国家兴&#xff0c;教育强则国家强。党的二十大报告指出&#xff0c;“加快建设教育强国”&#xff0c;并提出到2035年“建成教育强国”的总体目标。随着数字时代的到来&#xff0c;以物联网、大数据、云计算和人工智能为代表的数字技…

Seal^_^【送书活动第4期】——《Web渗透测试技术》

Seal^_^【送书活动第4期】——《Web渗透测试技术》 一、参与方式二、本期推荐图书2.1 前 言2.2 关于本书2.3 本书读者2.4 图书简介2.5 作者荐语2.6 编辑推荐2.7 目 录 三、正版购买 掌握Web渗透测试技术&#xff0c;提高Web应用安全性。 一、参与方式 1、关注博主的账号。 2、点…

The Quantcast File System——论文泛读

VLDB 2013 Paper 分布式元数据论文阅读笔记整理 问题 在2013年之前&#xff0c;由于网络链路带宽有限&#xff0c;数据在集群中移动速度慢&#xff0c;因此Hadoop尽量将数据留在原来的位置&#xff0c;并将处理代码发送给它。随着网络链路的发展&#xff0c;可以之前更高的数…

【多人协作】场景模拟(一)

文章目录 实现多人协作场景&#xff1a;操作流程1开发人员a和b克隆仓库到本地2在本地仓库建立分支并与远程分支建立链接3开发人员工作并提交代码4将合并dev分支与master分支 实现多人协作 多人协作开发是git的最核心也是最重要的操作。多人协作也就意味着同一时间里&#xff0…

快速传输大文件:手机电脑互传文件的最佳解决方案

无论是工作还是生活&#xff0c;我们都可能需要将照片、视频、音乐或其他类型的文件从一台设备发送到另一台设备。然而&#xff0c;由于网络速度的限制&#xff0c;传统的文件传输方法可能会非常耗时。那么&#xff0c;有没有一种快速传输大文件的解决方案呢&#xff1f;答案是…

基于IDEA快速创建一个SpringMVC项目并且配置Tomcat

1&#xff0c;打开IDEA&#xff0c;新建Maven项目【使用web模板创建】 使用社区版的同学创建普通的maven项目&#xff0c;并配置项目的webapp&#xff0c;详情可参考 快速创建一个SpringMVC项目&#xff08;IDEA&#xff09; 2&#xff0c;在main目录下创建Java和resource目录…

YOLOv9独家原创改进: 特征融合创新 | 一种基于内容引导注意力(CGA)的混合融合 | IEEE TIP 2024 浙大

💡💡💡创新点:提出了一种基于内容引导注意力(CGA)的混合融合方案,将编码器部分的低级特征与相应的高级特征有效融合。 💡💡💡在多个数据集实现暴力涨点,适用于小目标,低对比度场景 💡💡💡如何跟YOLOv9结合:将backbone和neck的特征融合,改进结构图如下…