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

C#开发FFMPEG例子(API方式) FFmpeg推送udp组播流

代码及工程见https://download.csdn.net/download/daqinzl/88156926

开发工具:visual studio 2019

播放,可采用ffmpeg工具集里的ffplay.exe, 执行命令 ffplay udp://238.1.1.10:6016
也可以参考(C#开发FFMPEG例子(API方式) FFmpeg拉取udp组播流并播放) https://blog.csdn.net/daqinzl/article/details/132112075

网上用C/C++调用FFmpeg的API例子很多,
c#使用ffmpeg.autogen的方式很简单,直接复制C/C++调用FFmpeg的API的代码到C#中,然后在FFmpeg的方法前加上ffmpeg.即可。

C/C++调用FFmpeg的API推送udp组播流的例子可以参考:https://blog.csdn.net/daqinzl/article/details/132080204

主要参考文档(C#开发FFMPEG例子(API方式) FFmpeg拉取RTMP流并播放):https://blog.csdn.net/vanjoge/article/details/79657874
参考文档实现了拉取rtmp流并播放,本文在参考文档提供的源码的基础上,结合C/C++调用FFmpeg的API的例子,做了一些修改,用C#使用ffmpeg.autogen实现推送udp组播流。

主要代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

using FFmpeg.AutoGen;

namespace FFmpegDemo
{
    static unsafe class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            //Application.EnableVisualStyles();
            //Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new frmPlayer());

            //FFmpegDLL目录查找和设置
            FFmpegBinariesHelper.RegisterFFmpegBinaries();

            ffmpeg.av_register_all();
            ffmpeg.avdevice_register_all();
            ffmpeg.avcodec_register_all();
            ffmpeg.avformat_network_init();

            AVFormatContext* m_fmt_ctx = null;
            AVInputFormat* m_input_fmt = null;
            int video_stream = -1;
            
            //ffmpeg.avcodec_register_all();
            string deviceName = "desktop";
            string inputformat = "gdigrab";
            int FPS = 23;  //15
            m_fmt_ctx = ffmpeg.avformat_alloc_context();
            m_input_fmt = ffmpeg.av_find_input_format(inputformat);
            AVDictionary* deoptions = null;
            ffmpeg.av_dict_set_int(&deoptions, "framerate", FPS, ffmpeg.AV_DICT_MATCH_CASE);
            ffmpeg.av_dict_set_int(&deoptions, "rtbufsize", 3041280 * 100 * 5, 0);

            //如果不设置的话,在输入源是直播流的时候,会花屏。单位bytes
            //av_dict_set(&deoptions, "buffer_size", "10485760", 0);
            //av_dict_set(&deoptions, "reuse", "1", 0);

            int ret = ffmpeg.avformat_open_input(&m_fmt_ctx, deviceName, m_input_fmt, &deoptions);
            if (ret != 0)
            {
                return;
            }
            ffmpeg.av_dict_free(&deoptions);
            ret = ffmpeg.avformat_find_stream_info(m_fmt_ctx, null);
            if (ret < 0)
            {
                return;
            }
            ffmpeg.av_dump_format(m_fmt_ctx, 0, deviceName, 0);
            video_stream = ffmpeg.av_find_best_stream(m_fmt_ctx, 0, -1, -1, null, 0);  //AVMEDIA_TYPE_VIDEO
            if (video_stream < 0)
            {
                return;
            }

            AVCodecContext* _codec_ctx = m_fmt_ctx->streams[video_stream]->codec;
            AVCodec* _codec = ffmpeg.avcodec_find_decoder(_codec_ctx->codec_id);
            if (_codec == null)
            {
                return;
            }
            ret = ffmpeg.avcodec_open2(_codec_ctx, _codec, null);
            if (ret != 0)
            {
                return;
            }
            int width = m_fmt_ctx->streams[video_stream]->codec->width;
            int height = m_fmt_ctx->streams[video_stream]->codec->height;
            int fps = m_fmt_ctx->streams[video_stream]->codec->framerate.num > 0 ? m_fmt_ctx->streams[video_stream]->codec->framerate.num : 25;
            AVPixelFormat videoType = m_fmt_ctx->streams[video_stream]->codec->pix_fmt;
            //std::cout << "avstream timebase : " << m_fmt_ctx->streams[video_stream]->time_base.num << " / " << m_fmt_ctx->streams[video_stream]->time_base.den << endl;
            Console.WriteLine("avstream timebase : " + m_fmt_ctx->streams[video_stream]->time_base.num + " / " + m_fmt_ctx->streams[video_stream]->time_base.den);

            AVDictionary* enoptions = null;
            //av_dict_set(&enoptions, "preset", "superfast", 0);
            //av_dict_set(&enoptions, "tune", "zerolatency", 0);
            ffmpeg.av_dict_set(&enoptions, "preset", "ultrafast", 0);
            ffmpeg.av_dict_set(&enoptions, "tune", "zerolatency", 0);

            //TODO
            //av_dict_set(&enoptions, "pkt_size", "1316", 0);    //Maximum UDP packet size
            av_dict_set(&dic, "fifo_size", "18800", 0);
            av_dict_set(&enoptions, "buffer_size", "0", 1);
            av_dict_set(&dic, "bitrate", "11000000", 0);
            av_dict_set(&dic, "buffer_size", "1000000", 0);//1316
            //av_dict_set(&enoptions, "reuse", "1", 0);

            AVCodec* codec = ffmpeg.avcodec_find_encoder(AVCodecID.AV_CODEC_ID_H264);
            if (codec == null)
            {
                Console.WriteLine( "avcodec_find_encoder failed!" );
                return;
            }
            AVCodecContext* vc = ffmpeg.avcodec_alloc_context3(codec);
            if (vc == null)
            {
                Console.WriteLine("avcodec_alloc_context3 failed!" );
                return;
            }
            Console.WriteLine("avcodec_alloc_context3 success!" );// FFmpeg.AutoGen.
           vc->flags |= (1 << 22);   //AV_CODEC_FLAG_GLOBAL_HEADER
            vc->codec_id = AVCodecID.AV_CODEC_ID_H264;
            vc->codec_type = FFmpeg.AutoGen.AVMediaType.AVMEDIA_TYPE_VIDEO;
            vc->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
            vc->width = width;
            vc->height = height;
            vc->time_base.num = 1;
            vc->time_base.den = FPS;
            //vc->framerate = { FPS,1 };
            //TODO
            vc->framerate.num = 1;
            vc->framerate.den = FPS;

            vc->bit_rate = 10241000;
            vc->gop_size = 120;
            vc->qmin = 10;
            vc->qmax = 51;
            vc->max_b_frames = 0;
            vc->profile = ffmpeg.FF_PROFILE_H264_MAIN;
            ret = ffmpeg.avcodec_open2(vc, codec, &enoptions);
            if (ret != 0)
            {
                return;
            }
            Console.WriteLine( "avcodec_open2 success!" );
            ffmpeg.av_dict_free(&enoptions);
            SwsContext* vsc = null;
            vsc = ffmpeg.sws_getCachedContext(vsc,
                width, height, (AVPixelFormat)videoType, //源宽、高、像素格式
                width, height, AVPixelFormat.AV_PIX_FMT_YUV420P,//目标宽、高、像素格式
                ffmpeg.SWS_BICUBIC, // 尺寸变化使用算法
                null, null, null
            );
            if (vsc==null)
            {
                Console.WriteLine("sws_getCachedContext failed!");
                return;
            }
            AVFrame* yuv = ffmpeg.av_frame_alloc();
            yuv->format = (int)AVPixelFormat.AV_PIX_FMT_YUV420P;
            yuv->width = width;
            yuv->height = height;
            yuv->pts = 0;
            ret = ffmpeg.av_frame_get_buffer(yuv, 32);
            if (ret != 0)
            {
                return;
            }
            //string rtmpurl = "rtmp://192.168.0.105:1935/live/desktop";            
            string rtmpurl = "udp://224.1.1.1:5001";
            AVFormatContext* ic = null;
            //ret = ffmpeg.avformat_alloc_output_context2(&ic, null, "flv", rtmpurl);            
            ret = ffmpeg.avformat_alloc_output_context2(&ic, null, "mpegts", rtmpurl);//UDP

            if (ret < 0)
            {
                return;
            }
            AVStream* st = ffmpeg.avformat_new_stream(ic, null);
            if (st == null)
            {
                return;
            }
            st->codecpar->codec_tag = 0;
            ffmpeg.avcodec_parameters_from_context(st->codecpar, vc);
            ffmpeg.av_dump_format(ic, 0, rtmpurl, 1);
            ret = ffmpeg.avio_open(&ic->pb, rtmpurl, ffmpeg.AVIO_FLAG_WRITE);
            if (ret != 0)
            {
                return;
            }
            ret = ffmpeg.avformat_write_header(ic, null);
            if (ret != 0)
            {
                return;
            }
            AVPacket* packet = ffmpeg.av_packet_alloc();
            AVPacket* Encodepacket = ffmpeg.av_packet_alloc();
            int frameIndex = 0;
            int EncodeIndex = 0;
            AVFrame* rgb = ffmpeg.av_frame_alloc();
            AVBitStreamFilterContext* h264bsfc = ffmpeg.av_bitstream_filter_init("h264_mp4toannexb");
            long startpts = m_fmt_ctx->start_time;
            long lastpts = 0;
            AVRational bq = new AVRational(); bq.num = 1; bq.den = FPS;
            AVRational cq = new AVRational(); cq.num = 1; cq.den = ffmpeg.AV_TIME_BASE;
            long duration = ffmpeg.av_rescale_q(1, bq, cq);
            int got_picture = 0;
            while (frameIndex < 2000000)
            {
                ret = ffmpeg.av_read_frame(m_fmt_ctx, packet);
                if (ret < 0)
                {
                    break;
                }
                if (packet->stream_index == video_stream)
                {
                    ret = ffmpeg.avcodec_decode_video2(_codec_ctx, rgb, &got_picture, packet);
                    if (ret < 0)
                    {
                        Console.WriteLine("Decode Error.\n");
                        return;
                    }
                    if (got_picture != null)
                    {
                        int h = ffmpeg.sws_scale(vsc, rgb->data, rgb->linesize, 0, height, //源数据
                            yuv->data, yuv->linesize);
                        long guesspts = frameIndex * duration;
                        yuv->pts = guesspts;
                        frameIndex++;
                        ret = ffmpeg.avcodec_encode_video2(vc, Encodepacket, yuv, &got_picture);
                        if (ret < 0)
                        {
                            Console.WriteLine("Failed to encode!\n");
                            break;
                        }
                        if (got_picture == 1)
                        {
                            Encodepacket->pts = ffmpeg.av_rescale_q(EncodeIndex, vc->time_base, st->time_base);
                            Encodepacket->dts = Encodepacket->pts;
                            //std::cout << "frameindex : " << EncodeIndex << " pts : " << Encodepacket->pts << " dts: " << Encodepacket->dts << " encodeSize:" << Encodepacket->size << " curtime - lasttime " << Encodepacket->pts - lastpts << endl;
                            Console.WriteLine("frameindex : " + EncodeIndex.ToString() + " pts : " + Encodepacket->pts.ToString() + " dts: " + Encodepacket->dts.ToString() + " encodeSize:" + Encodepacket->size.ToString() + " curtime - lasttime " + (Encodepacket->pts - lastpts).ToString());
                            lastpts = Encodepacket->pts;
                            ret = ffmpeg.av_interleaved_write_frame(ic, Encodepacket);
                            EncodeIndex++;
                            ffmpeg.av_packet_unref(Encodepacket);
                        }
                    }
                }
                ffmpeg.av_packet_unref(packet);
            }
            ret = ffmpeg.avcodec_send_frame(vc, null);
            while (ret >= 0)
            {
                ret = ffmpeg.avcodec_receive_packet(vc, Encodepacket);
                if (ret == ffmpeg.AVERROR(ffmpeg.EAGAIN) || ret == ffmpeg.AVERROR_EOF)
                {
                    break;
                }
                if (ret < 0)
                {
                    break;
                }
                ret = ffmpeg.av_interleaved_write_frame(ic, Encodepacket);
                EncodeIndex++;
            }
            ffmpeg.av_write_trailer(ic);
            ffmpeg.av_packet_free(&packet);
            ffmpeg.av_packet_free(&Encodepacket);
            ffmpeg.av_frame_free(&rgb);
            ffmpeg.av_frame_free(&yuv);
            ffmpeg.av_bitstream_filter_close(h264bsfc);
            h264bsfc = null;
            if (vsc != null)
            {
                ffmpeg.sws_freeContext(vsc);
                vsc = null;
            }
            if (_codec_ctx != null)
                ffmpeg.avcodec_close(_codec_ctx);
            _codec_ctx = null;
            _codec = null;
            if (vc != null)
                ffmpeg.avcodec_free_context(&vc);
            if (m_fmt_ctx != null)
                ffmpeg.avformat_close_input(&m_fmt_ctx);
            if (ic!=null && (ic->flags & ffmpeg.AVFMT_NOFILE)==0)
                ffmpeg.avio_closep(&ic->pb);
            if (ic != null)
            {
                ffmpeg.avformat_free_context(ic);
                ic = null;
            }
            m_input_fmt = null;
            return;

        }
    }
}
 

相关文章:

C#开发FFMPEG例子(API方式) FFmpeg推送udp组播流

代码及工程见https://download.csdn.net/download/daqinzl/88156926 开发工具&#xff1a;visual studio 2019 播放&#xff0c;可采用ffmpeg工具集里的ffplay.exe, 执行命令 ffplay udp://238.1.1.10:6016 也可以参考(C#开发FFMPEG例子(API方式) FFmpeg拉取udp组播流并播放)…...

nvm下载node导致npm报错无法使用

有个依赖库需要更新下node&#xff0c;用nvm下载后项目跑不起来了&#xff0c;npm -v 还报错 其实一开始是npm下载不来&#xff0c;然后换了淘宝镜像后还是报错 然后就只能手动下载下了 进入node.js官网 https://nodejs.org/en/download 下载后注意要安装在你nvm目录中&#x…...

LeetCode 热题 100JavaScript--2. 两数相加

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …...

zookeeper总结

1.概念 Zookeeper 是一个分布式协调服务&#xff0c;可用于服务发现&#xff0c;分布式锁&#xff0c;分布式领导选举&#xff0c;配置管理等。Zookeeper 提供了一个类似于 Linux 文件系统的树形结构&#xff08;可认为是轻量级的内存文件系统&#xff0c;但只适合存少量信息&…...

【程序环境与预处理玩转指南】

本章重点&#xff1a; 程序的翻译环境 程序的执行环境 详解&#xff1a;C语言程序的编译链接 预定义符号介绍 预处理指令 #define 宏和函数的对比 预处理操作符#和##的介绍 命令定义 预处理指令 #include 预处理指令 #undef 条件编译 1. 程序的翻译环境和执行环境 在…...

搭建简易syslog日志中转服务器

在某种场景下&#xff0c;无法接入日志审计设备&#xff0c;本文提供一种方式&#xff0c;可通过搭建简易日志中转服务器&#xff0c;收集到该环境下的日志后&#xff0c;再将其导入日志审计设备中。 0x1 开启服务 rsyslog守护进程来自于当前的linux发布版本的预装模块&#x…...

MongoDB文档-进阶使用-spring-boot整合使用MongoDB---MongoRepository完成增删改查

阿丹&#xff1a; 之前学习了在MongoDB客户端上的MongoDB语句现在将MongoDB整合到spring项目。 传送门&#xff1a; MongoDB文档--基本概念_一单成的博客-CSDN博客 MongoDB文档--基本安装-linux安装&#xff08;mongodb环境搭建&#xff09;-docker安装&#xff08;挂载数据卷…...

什么是线程局部变量?

在Java中&#xff0c;线程局部变量(Thread Local Variable)是一种特殊类型的变量&#xff0c;每个线程都有其自己独立的副本。这意味着每个线程可以在该变量上进行操作&#xff0c;而不会影响其他线程的副本。线程局部变量通常用于在多线程环境中存储线程私有的数据&#xff0c…...

Jmeter响应中的乱码问题

文章目录 问题描述解决办法 问题描述 Jmeter在访问接口的时候&#xff0c;响应内容如果有中文可能会显示乱码 响应页面没有做编码处理&#xff0c;JMeter默认按照ISO-8859-1编码格式进行解析 解决办法 在线程组中添加BeanShell PostProcessor后置处理器 prev.setDataEnco…...

MongoDB文档-进阶使用-MongoDB索引-createindex()与dropindex()-在MongoDB中使用正则表达式来查找

阿丹&#xff1a; 之前研究了MongoDB的基础增删改查。在学会基础的数据库增删改查肯定是不够的。这个时候就涉及到了数据库搜索的时候的效率。需要提高数据的搜索效率。 MongoDB索引 在所以数据库中如果没有数据索引的时候。如果需要查找到一些数据。都会去主动扫描所有可能存…...

CentOS下ZLMediaKit的可视化管理网站MediaServerUI使用

一、简介 按照 ZLMediaKit快速开始 编译运行ZLMediaKit成功后&#xff0c;我们可以运行其合作开源项目MediaServerUI&#xff0c;来对ZLMediaKit进行可视化管理。通过MediaServerUI&#xff0c;我们可以实现在浏览器查看ZLMediaKit的延迟率、负载率、正在进行的推拉流、服务器…...

回归预测 | MATLAB实现POA-CNN-BiGRU鹈鹕算法优化卷积双向门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现POA-CNN-BiGRU鹈鹕算法优化卷积双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现POA-CNN-BiGRU鹈鹕算法优化卷积双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现POA-CNN-BiGRU鹈鹕…...

Rust 原生支持龙架构指令集

导读近日&#xff0c;Rust 开源社区发布 1.71.0 版本&#xff0c;实现对龙架构&#xff08;LoongArch&#xff09;指令集的原生支持。 龙架构操作系统发行版和开发者可基于上游社区源代码构建或直接下载 Rust 开源社区发布的龙架构二进制版本。Rust 开发者将在龙架构平台上获得…...

为生成式AI提速,亚马逊云科技Amazon EC2 P5满足GPU需求

生成式AI&#xff08;Generative AI&#xff09;已经成为全球范围内的一个重要趋势&#xff0c;得到越来越多企业和研究机构的关注和应用。纽约时间7月26日&#xff0c;亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian在亚马逊云科技举办的纽约峰会上更…...

聊聊企业数据安全那些事~

保护企业数据安全的重要性与方法 随着信息技术的快速发展&#xff0c;企业数据的安全性变得越来越重要。在数字化时代&#xff0c;企业的核心业务和关键信息都存储在电脑系统中&#xff0c;一旦遭受到数据泄露、黑客攻击或恶意软件感染&#xff0c;将可能对企业造成严重的损害…...

日常随笔——如何把excel题库转换为word打印格式

将Excel题库转换为Word可以通过编程的方式实现。以下是一个使用Python的示例代码&#xff0c;该代码使用openpyxl库读取Excel文件&#xff0c;并使用python-docx库创建和保存Word文档。 首先&#xff0c;请确保已经安装了 openpyxl 和 python-docx 库。可以使用以下命令进行安…...

SpringCloud项目打包注意事项以及可能出错的几种情况

SpringCloud项目打包注意事项和可能出错的几种情况 1、检查子模块中的 parent的pom文件路径 \<relativePath/\>2、检查打包插件的位置3、检查module是否重复引用 欢迎访问我的个人博客&#xff1a;https://wk-blog.vip 1、检查子模块中的 parent的pom文件路径 <relat…...

ZABBIX 6.4 Mysql数据库分表

ZABBIX监控设备较多的时候&#xff0c;Mysql数据库容易成为性能的瓶颈&#xff0c;可以通过数据库分表的方式来进行优化。步骤如下&#xff1a; 一、停用zabbix服务 # 避免修改分区表时&#xff0c;数据还有写入 systemctl stop zabbix 二、备份MySQL zabbix DB 避免修改分…...

多线程-Runable和Callable的区别

在Java中&#xff0c;多线程可以通过实现Runnable接口或使用Callable接口来实现。这两种方式有一些区别&#xff0c;如下所示&#xff1a; 返回值&#xff1a; Runnable接口的run()方法没有返回值&#xff0c;它表示一个没有返回结果的任务。Callable接口的call()方法有返回值…...

智慧城市规划新引擎:探秘数字孪生中的二维与三维GIS技术差异

智慧城市作为人类社会发展的新阶段&#xff0c;正日益引领着我们迈向数字化未来的时代。在智慧城市的建设过程中&#xff0c;地理信息系统&#xff08;GIS&#xff09;扮演着举足轻重的角色。而在GIS的发展中&#xff0c;二维和三维GIS作为两大核心技术&#xff0c;在城市规划与…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

【多线程初阶】单例模式 指令重排序问题

文章目录 1.单例模式1)饿汉模式2)懒汉模式①.单线程版本②.多线程版本 2.分析单例模式里的线程安全问题1)饿汉模式2)懒汉模式懒汉模式是如何出现线程安全问题的 3.解决问题进一步优化加锁导致的执行效率优化预防内存可见性问题 4.解决指令重排序问题 1.单例模式 单例模式确保某…...

【2D与3D SLAM中的扫描匹配算法全面解析】

引言 扫描匹配(Scan Matching)是同步定位与地图构建(SLAM)系统中的核心组件&#xff0c;它通过对齐连续的传感器观测数据来估计机器人的运动。本文将深入探讨2D和3D SLAM中的各种扫描匹配算法&#xff0c;包括数学原理、实现细节以及实际应用中的性能对比&#xff0c;特别关注…...

旋量理论:刚体运动的几何描述与机器人应用

旋量理论为描述刚体在三维空间中的运动提供了强大而优雅的数学框架。与传统的欧拉角或方向余弦矩阵相比&#xff0c;旋量理论通过螺旋运动的概念统一了旋转和平移&#xff0c;在机器人学、计算机图形学和多体动力学领域具有显著优势。这种描述不仅几何直观&#xff0c;而且计算…...

docker 部署redis集群 配置

docker的网络模式 网桥模式每次重启容器都有可能导致容器ip地址变化&#xff0c;需要固定ip的自己自定义网络&#xff0c;这里介绍的是默认网络模式 docker创建容器 docker run --name redis6379 -p 6379:6379 -p 16379:16379 -v /etc/redis/redis6379:/etc/redis -d --r…...

SpringBoot+MySQL家政服务平台 设计开发

概述 基于SpringBootMySQL开发的家政服务平台完整项目&#xff0c;该系统实现了用户预约、服务管理、订单统计等核心功能&#xff0c;采用主流技术栈开发&#xff0c;代码规范且易于二次开发。 主要内容 系统功能架构 本系统采用前后端分离架构&#xff0c;前端提供用户交互…...