通过多线程分别获取高分辨率和低分辨率的H264码流

目录

一.RV1126 VI采集摄像头数据并同时获取高分辨率码流和低分辨率码流流程

​编辑

1.1初始化VI模块:

1.2初始化RGA模块:

1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:

1.4 VI绑定高分辨率VENC编码器,VI绑定RGA模块,伪代码如下:

1.5 创建多线程获取高分辨率编码数据:

1.6 创建多线程获取低分辨率数据并传输到编码器:

1.7.创建多线程获取低分辨率编码数据:

三.运行的效果:


一.RV1126 VI采集摄像头数据并同时获取高分辨率码流和低分辨率码流流程

RV1126利用多线程同时获取高分辨率编码文件、低分辨率编码文件,一般要分为上图8个步骤:VI模块初始化RGA图像模块初始化、高分辨率编码器的初始化、低分辨率编码器的初始化、VI绑定高分辨率VENC编码器、创建多线程获取高分辨率编码数据、创建多线程获取低分辨率数据并传输到编码器、创建多线程获取低分辨率编码数据。

1.1初始化VI模块:

VI模块的初始化实际上就是对VI_CHN_ATTR_S的参数进行设置、然后调用RK_MPI_VI_SetChnAttr设置VI模块并使能RK_MPI_VI_EnableChn,伪代码如下:

VI_CHN_ATTR_S  vi_chn_attr;

。。。。。。。。。。。。。。。(这里是设置VI的属性)

ret = RK_MPI_VI_SetChnAttr(CAMERA_ID, 0, &vi_chn_attr);

ret |= RK_MPI_VI_EnableChn(CAMERA_ID, 0);

1.2初始化RGA模块:

RGA主要的作用是缩放VI模块的分辨率,比方说:VI模块的分辨率1920 * 1080,经过RGA缩放后分辨率为1280 * 720,并利用RK_MPI_RGA_CreateChn创建RGA模块,伪代码如下:

RGA_ATTR_S rga_attr;

rga_attr.stImgIn.u32Width = 1920;

rga_attr.stImgIn.u32Height = 1080;

。。。。。。。。。

rga_attr.stImgOut.u32Width = 1280;

rga_attr.stImgOut.u32Height = 720;

。。。。。。。。。。。

RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_attr);

这段代码的核心是输入图像(输入分辨率是原分辨率和VI模块一致)和输出分辨率(输出分辨率是自己设置的分辨率)的设置。比方说输入的分辨率是 : 1920*1080,那stImgIn.u32Width = 1920 、stImgIn.u32Height = 1080,输出图像成:1280 * 720,stImgOut.u32Width = 1280、stImgOut.u32Height = 720。

1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:

高分辨率编码器的初始化

VENC_CHN_ATTR_S high_venc_chn_attr;

high_venc_chn_attr.stVencAttr.u32PicWidth = 1920;

high_venc_chn_attr.stVencAttr.u32PicHeight = 1080;

high_venc_chn_attr.stVencAttr.u32VirWidth = 1920;

high_venc_chn_attr.stVencAttr.u32VirHeight = 1080;

................................

RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &high_venc_chn_attr);

低分辨率编码器的初始化

VENC_CHN_ATTR_S low_venc_chn_attr;

low_venc_chn_attr.stVencAttr.u32PicWidth = 1280;

low_venc_chn_attr.stVencAttr.u32PicHeight = 720;

low_venc_chn_attr.stVencAttr.u32VirWidth = 1280;

low_venc_chn_attr.stVencAttr.u32VirHeight = 720;

................................

RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &low_venc_chn_attr);

高分辨率和低分辨率最核心的设置就是分辨率的设置,高分辨率u32PicWidth = 1920、u32PicHeight = 1920,低分辨率u32PicWidth = 1280、u32PicHeight = 720

1.4 VI绑定高分辨率VENC编码器,VI绑定RGA模块,伪代码如下:

//VI模块绑定RGA模块

MPP_CHN_S vi_chn_s;

vi_chn_s.enModId = RK_ID_VI;

vi_chn_s.s32ChnId = CAMERA_CHN;

MPP_CHN_S rga_chn_s;

rga_chn_s.enModId = RK_ID_RGA;

rga_chn_s.s32ChnId = RGA_CHN_ID;

RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s);

//VI模块绑定高分辨率VENC模块

MPP_CHN_S high_venc_chn_s;

high_venc_chn_s_s.enModId = RK_ID_VENC;

high_venc_chn_s_s.s32ChnId = HIGH_VENC_ID;

RK_MPI_SYS_Bind(&vi_chn_s, &high_venc_chn_s);

1.5 创建多线程获取高分辨率编码数据:

开启一个线程去采集每一帧高分辨率的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是高分辨率VENC创建的ID号:

while(1)

{

  .........................

  mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, HIGH_VENC_ID, -1);

  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1,high_venc_id);

.......................

}

1.6 创建多线程获取低分辨率数据并传输到编码器:

开启一个线程去采集每一帧RGA低分辨率的数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_RGA,通道号ID是RGA的通道ID,采集完每一帧RGA数据则使用RK_MPI_SYS_SendMediaBuffer传输到低分辨率编码器这个API伪代码如下

while (1)

{

.........................................

mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, 0, -1);

    RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, LOW_VENC_ID, mb);

................................

}

下面我们来看看RK_MPI_SYS_SendMediaBuffer的具体实现

RK_S32 RK_MPI_SYS_SendMediaBuffer(MOD_ID_E enModID, RK_S32 s32ChnID, MEDIA_BUFFER buffer);

enModID:开发者需要传输的目的模块的ID号,比方说VI模块的数据传输到VENC模块,那么目的模块就是VENC,ID号就是RK_ID_VENC;比方说VI模块的数据传输到RGA模块,那么目的模块就是RGA,ID号就是RK_ID_RGA。

s32ChnID:目的模块的通道号

buffer:缓冲区数据MediaBuffer

1.7.创建多线程获取低分辨率编码数据:

开启一个线程去采集每一帧低分辨率的编码数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是低分辨率VENC创建的ID号这个API伪代码如下

while (1)

{

.........................................

mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, LOW_VENC_ID, -1);

fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, low_venc_file);

................................

}

二.代码实战

#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

// #include "common/sample_common.h"
#include "rkmedia_api.h"

#define PIPE_ID 0
#define VI_CHN_ID 0

#define RGA_CHN_ID 0

#define HIGH_VENC_CHN 0
#define LOW_VENC_CHN 1

//创建多线程获取高分辨率的编码码流
void *get_high_venc_thread(void *args)
{
    pthread_detach(pthread_self());
    FILE *high_venc_file = fopen("test_high_venc.h264", "w+");
    MEDIA_BUFFER mb;

    while (1)
    {
        //获取每一帧高分辨率编码码流数据
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, HIGH_VENC_CHN, -1);
        if (!mb)
        {
            printf("Get High Venc break.....\n");
        }

        printf("Get High Venc Success.....\n");
        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, high_venc_file);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}

//创建多线程获取RGA码流并发送到低分辨率编码器
void *rga_handle_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;

    while (1)
    {
         //获取每一帧RGA码流数据
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, RGA_CHN_ID, -1);
        if (!mb)
        {
            printf("Get RGA break.....\n");
        }

        printf("Get RGA Success.....\n");
        //发送每一帧RGA数据到低分辨率编码器
        RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, mb);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}

//创建多线程获取低分辨率编码码流
void *get_low_venc_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    FILE * low_venc_file = fopen("test_low_venc.h264", "w+");

    while (1)
    {
        //获取每一帧低分辨率编码码流
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, -1);
        if (!mb)
        {
            printf("Get LOW VENC break.....\n");
        }

        printf("Get LOW VENC Success.....\n");
        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, low_venc_file);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}

int main(int argc, char *argv[])
{

    int ret;
    RK_MPI_SYS_Init();

    // VI Init......
    VI_CHN_ATTR_S vi_chn_attr;
    vi_chn_attr.pcVideoNode = "rkispp_scale0";//设置视频设备节点路径
    vi_chn_attr.u32Width = 1920;//设置分辨率的宽度
    vi_chn_attr.u32Height = 1080;//设置分辨率的高度
    vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;//设置图像类型
    vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;//设置VI获取类型
    vi_chn_attr.u32BufCnt = 3;//设置缓冲数量
    vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;//设置VI工作类型
    ret = RK_MPI_VI_SetChnAttr(PIPE_ID, VI_CHN_ID, &vi_chn_attr);
    if (ret)
    {
        printf("VI_CHN_ATTR Set Failed.....\n");
        return -1;
    }
    else
    {
        printf("VI_CHN_ATTR Set Success.....\n");
    }

    ret = RK_MPI_VI_EnableChn(PIPE_ID, VI_CHN_ID);
    if (ret)
    {
        printf("VI_CHN_ATTR Enable Failed.....\n");
        return -1;
    }
    else
    {
        printf("VI_CHN_ATTR Enable Success.....\n");
    }

    // RGA
    RGA_ATTR_S rga_info;
    /**Image Input ..............*/
    rga_info.stImgIn.u32Width = 1920;//设置RGA输入分辨率宽度
    rga_info.stImgIn.u32Height = 1080;//设置RGA输入分辨率高度
    rga_info.stImgIn.u32HorStride = 1920;//设置RGA输入分辨率虚宽
    rga_info.stImgIn.u32VirStride = 1080;//设置RGA输入分辨率虚高
    rga_info.stImgIn.imgType = IMAGE_TYPE_NV12;//设置ImageType图像类型
    rga_info.stImgIn.u32X = 0;//设置X坐标
    rga_info.stImgIn.u32Y = 0;//设置Y坐标

    /**Image Output......................*/
    rga_info.stImgOut.u32Width = 1280;//设置RGA输出分辨率宽度
    rga_info.stImgOut.u32Height = 720;//设置RGA输出分辨率高度
    rga_info.stImgOut.u32HorStride = 1280;//设置RGA输出分辨率虚宽
    rga_info.stImgOut.u32VirStride = 720;//设置RGA输出分辨率虚高
    rga_info.stImgOut.imgType = IMAGE_TYPE_NV12;//设置输出ImageType图像类型
    rga_info.stImgOut.u32X = 0;//设置X坐标
    rga_info.stImgOut.u32Y = 0;//设置Y坐标

    // RGA Public Parameter
    rga_info.u16BufPoolCnt = 3;//缓冲池计数
    rga_info.u16Rotaion = 0;//
    rga_info.enFlip = RGA_FLIP_H;//水平翻转
    rga_info.bEnBufPool = RK_TRUE;
    ret = RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_info);
    if (ret)
    {
        printf("RGA Set Failed.....\n");
    }
    else
    {
        printf("RGA Set Success.....\n");
    }

    // High Venc Parameter
    VENC_CHN_ATTR_S high_venc_attr;
    high_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;//设置编码器类型
    high_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型
    high_venc_attr.stVencAttr.u32PicWidth = 1920;//设置编码分辨率宽度
    high_venc_attr.stVencAttr.u32PicHeight = 1080;//设置编码分辨率高度
    high_venc_attr.stVencAttr.u32VirWidth = 1920;//设置编码分辨率虚宽
    high_venc_attr.stVencAttr.u32VirHeight = 1080;//设置编码分辨率虚高
    high_venc_attr.stVencAttr.u32Profile = 66;//设置编码等级
    high_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度

    //********* 设置码率控制属性  *******************//
    high_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//设置H264的CBR码率控制模式
    high_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔
    high_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子
    high_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//设置源帧率分母
    high_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子
    high_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母
    high_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;//设置码率大小
    ret = RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &high_venc_attr);
    if (ret)
    {
        printf("Set High Venc Attr Failed.....\n");
    }
    else
    {
        printf("Set High Venc Attr Success.....\n");
    }

    // Low Venc Parameter
    VENC_CHN_ATTR_S low_venc_attr;
    low_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;//设置编码器类型
    low_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型
    low_venc_attr.stVencAttr.u32PicWidth = 1280;//设置编码分辨率宽度
    low_venc_attr.stVencAttr.u32PicHeight = 720;//设置编码分辨率高度
    low_venc_attr.stVencAttr.u32VirWidth = 1280;//设置编码分辨率虚宽
    low_venc_attr.stVencAttr.u32VirHeight = 720;//设置编码分辨率虚高
    low_venc_attr.stVencAttr.u32Profile = 66;//设置编码等级
    low_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度

     //********* 设置码率控制属性  *******************//
    low_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//设置H264的CBR码率控制模式
    low_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔
    low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子
    low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//设置源帧率分母
    low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子
    low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母
    low_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;//设置码率大小
    ret = RK_MPI_VENC_CreateChn(LOW_VENC_CHN, &low_venc_attr);
    if (ret)
    {
        printf("Set Low Venc Attr Failed.....\n");
    }
    else
    {
        printf("Set Low Venc Attr Success.....\n");
    }

    MPP_CHN_S vi_chn_s;
    vi_chn_s.enModId = RK_ID_VI;
    vi_chn_s.s32ChnId = VI_CHN_ID;

    MPP_CHN_S high_chn_s;
    high_chn_s.enModId = RK_ID_VENC;
    high_chn_s.s32ChnId = HIGH_VENC_CHN;

    //VI绑定高分辨率VENC模块
    ret = RK_MPI_SYS_Bind(&vi_chn_s, &high_chn_s);
    if (ret)
    {
        printf("VI Bind High Venc Failed.....\n");
        return -1;
    }
    else
    {
        printf("VI Bind High Venc Success.....\n");
    }

    MPP_CHN_S rga_chn_s;
    rga_chn_s.enModId = RK_ID_RGA;
    rga_chn_s.s32ChnId = RGA_CHN_ID;

    //VI绑定RGA模块
    ret = RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s);
    if (ret)
    {
        printf("VI Bind RGA Failed.....\n");
        return -1;
    }
    else
    {
        printf("VI Bind RGA Success.....\n");
    }

    pthread_t high_venc_pid;
    pthread_t rga_pid;
    pthread_t low_venc_pid;

    pthread_create(&high_venc_pid, NULL, get_high_venc_thread, NULL); //创建多线程获取高分辨率的编码码流 
    pthread_create(&rga_pid, NULL, rga_handle_thread, NULL);//创建多线程获取RGA码流并发送到低分辨率编码器
    pthread_create(&low_venc_pid, NULL, get_low_venc_thread, NULL);//创建多线程获取低分辨率编码码流

    while (1)
    {
        sleep(1);
    }

    RK_MPI_SYS_UnBind(&vi_chn_s, &high_chn_s);
    RK_MPI_SYS_UnBind(&vi_chn_s, &rga_chn_s);
    RK_MPI_RGA_DestroyChn(RGA_CHN_ID);
    RK_MPI_VENC_DestroyChn(HIGH_VENC_CHN);
    RK_MPI_VENC_DestroyChn(LOW_VENC_CHN);
    RK_MPI_VI_DisableChn(PIPE_ID, VI_CHN_ID);

    return 0;
}

三.运行的效果:

分别用ffplay播放器分别播出高分辨率H264文件(test_high_venc.h264),低分辨率(test_rga_venc.h264)

ffplay test_high_venc.h264

ffplay test_rga_venc.h264

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python 数据结构 1.零基础复习】

目录 一、输入与输出 1.输入 2.格式化输出 二、数字与变量 1.字符串 & 整型 2.字符串 & 整型 & 浮点型 3.变量 练习 2235. 两整数相加 三、运算与操作 1.四则运算 练习 2769. 找出最大的可达成数字 3.取整与取余 练习 2651. 计算列车到站时间 ​编辑 四、真与假 1…

21. 构造二叉树(卡码网)

21. 构造二叉树 find&#xff08;&#xff09;方法 在Python中&#xff0c;str.find(sub[, start[, end]]) 方法用于查找子字符串 sub 在字符串中首次出现的位置&#xff0c;返回其起始索引。如果未找到&#xff0c;返回 -1 class Tree:def __init__(self,valNone,leftNone,r…

RocketMQ定时/延时消息实现机制

RocketMQ 的延迟消息是其核心特性之一&#xff0c;允许消息在指定延迟时间后才被消费者消费。 定时消息生命周期 一、延迟消息的核心机制 RocketMQ&#xff08;5.0之前&#xff09; 不支持任意时间精度的延迟&#xff0c;而是通过预定义的 延迟级别&#xff08;Delay Level&a…

【编程题】7-3 树的同构

7-3 树的同构 1 题目原文2 思路解析3 代码实现4 总结 1 题目原文 题目链接&#xff1a;7-3 树的同构 给定两棵树 T 1 T_1 T1​ 和 T 2 T_2 T2​​。如果 T 1 T_1 T1​ 可以通过若干次左右孩子互换就变成 T 2 T_2 T2​&#xff0c;则我们称两棵树是“同构”的。例如图 1 1 …

WebP2P技术在嵌入式设备中的应用:EasyRTC音视频通话SDK如何实现高效通信?

在数字化时代&#xff0c;实时通信技术&#xff08;RTC&#xff09;与人工智能&#xff08;AI&#xff09;的融合正在重塑各个行业的交互方式。从在线教育到远程医疗&#xff0c;从社交娱乐到企业协作&#xff0c;RTC的应用场景不断拓展。然而&#xff0c;传统的RTC解决方案往往…

【前端】前端设计中的响应式设计详解

文章目录 前言一、响应式设计的定义与作用二、响应式设计的原则三、响应式设计的实现四、响应式设计的最佳实践总结 前言 在当今数字化时代&#xff0c;网站和应用程序需要适应各种设备&#xff0c;从桌面电脑到平板电脑和手机。响应式设计应运而生&#xff0c;成为一种可以适…

【AVRCP】探寻AVRCP控制互操作性:连接、命令与设备交互

AVRCP对于实现设备间的高效音频/视频控制至关重要。而控制互操作性要求作为AVRCP的核心部分&#xff0c;详细规定了设备在连接建立、命令传输等方面的具体操作。确保了不同设备之间能够实现无缝的远程控制。 一、AVCTP连接管理 1.1 AVCTP连接建立 发起者&#xff1a;AVCTP控制…

LLM大型语言模型(一)

1. 什么是 LLM&#xff1f; LLM&#xff08;大型语言模型&#xff09;是一种神经网络&#xff0c;专门用于理解、生成并对人类文本作出响应。这些模型是深度神经网络&#xff0c;通常训练于海量文本数据上&#xff0c;有时甚至覆盖了整个互联网的公开文本。 LLM 中的 “大” …

2025国家护网HVV高频面试题总结来了04(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 一、HVV行动面试题分类 根据面试题的内容&#xff0c;我们将其分为以下几类&#xff1a; 漏洞利用与攻击技术 …

解锁GPM 2.0「卡顿帧堆栈」|代码示例与实战分析

每个游戏开发者都有一个共同的愿望&#xff0c;那就是能够在无需复现玩家反馈的卡顿现象时&#xff0c;快速且准确地定位卡顿的根本原因。为了实现这一目标&#xff0c;UWA GPM 2.0推出了全新功能 - 卡顿帧堆栈&#xff0c;旨在为开发团队提供高效、精准的卡顿分析工具。在这篇…

【人工智能】蓝耘智算平台盛大发布DeepSeek满血版:开创AI推理体验新纪元

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 蓝耘智算平台 蓝耘智算平台核心技术与突破元生代推理引擎快速入门&#xff1a;三步调用大模型接口&#xff0c;OpenAI SDK无缝兼容实战用例文…

用Python+Flask打造可视化武侠人物关系图生成器:从零到一的实战全记录

用PythonFlask打造可视化武侠人物关系图生成器&#xff1a;从零到一的实战全记录 一、缘起&#xff1a;一个程序小白的奇妙探索之旅 作为一个接触Python仅13天的编程萌新&#xff0c;我曾以为开发一个完整的应用是遥不可及的事情。但在DeepSeek的帮助下&#xff0c;我竟用短短…

Mac远程桌面软件哪个好用?

远程桌面软件能帮助我们快速的远程控制另一台电脑&#xff0c;从而提供远程帮助&#xff0c;或者进行远程办公。那么&#xff0c;对macOS系统有什么好用的Mac远程桌面软件呢&#xff1f; 远程看看是一款操作简单、界面简洁的远程桌面软件&#xff0c;支持跨平台操作&#xff0…

华为云 | 快速搭建DeepSeek推理系统

DeepSeek&#xff08;深度求索&#xff09;作为一款国产AI大模型&#xff0c;凭借其高性能、低成本和多模态融合能力&#xff0c;在人工智能领域崛起&#xff0c;并在多个行业中展现出广泛的应用潜力。 如上所示&#xff0c;在华为云解决方案实践中&#xff0c;华为云提供的快速…

Unity 内置渲染管线各个Shader的用途和性能分析,以及如何修改Shader(build in shader 源码下载)

文章目录 所有Shader分析路径&#xff1a;Standard路径&#xff1a;Nature/路径&#xff1a;UI/路径&#xff1a;Particles/Particles/Standard SurfaceParticles/Standard Unlit 路径&#xff1a;Unlit/Unlit/TextureUnlit/ColorUnlit/TransparentUnlit/Transparent CutoutUnl…

概率分布与概率密度

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 正文 &#x1f50d; 1. 概率分布基…

【C++】类与对象:深入理解默认成员函数

类与对象&#xff1a;深入理解默认成员函数 引言1、默认成员函数概述2、构造函数与析构函数2.1 默认构造函数2.2 析构函数 3、拷贝控制成员3.1 拷贝构造函数3.2 赋值运算符重载 4、移动语义&#xff08;C11&#xff09;4.1 移动构造函数4.2 移动赋值运算符 5、三五法则与最佳实…

LINUX网络基础 - 网络编程套接字,UDP与TCP

目录 前言 一. 端口号的认识 1.1 端口号的作用 二. 初识TCP协议和UDP协议 2.1 TCP协议 TCP的特点 使用场景 2.2 UDP协议 UDP的特点 使用场景 2.3 TCP与UDP的对比 2.4 思考 2.5 总结 三. 网络字节序 3.1 网络字节序的介绍 3.2 网络字节序思考 四. socket接口 …

夸父工具箱(安卓版) 手机超强工具箱

如今&#xff0c;人们的互联网活动日益频繁&#xff0c;导致手机内存即便频繁清理&#xff0c;也会莫名其妙地迅速填满&#xff0c;许多无用的垃圾信息悄然占据空间。那么&#xff0c;如何有效应对这一难题呢&#xff1f;答案就是今天新推出的这款工具软件&#xff0c;它能从根…

Apache nifi demo 实验

Apache nifi 是个数据流系统&#xff0c;可以通过配置 自定义的流程来实现数据的转换。 比如可以配置一个流程&#xff0c;读取数据库里的数据&#xff0c;再转换&#xff0c;最后保存到本地文件。 这样可以来实现一些数据转换的操作&#xff0c;而不用特地编写程序来导入导出。…