ffmpeg录制H265格式的桌面视频

news2025/1/15 12:58:17

ffmpeg本身不支持H265,如果需要支持,需要事先编译出libx265,读者可以到libx265的官方网站https://www.videolan.org/developers/x265.html上找到下载地址,本人下载的是x265_3.5.tar.gz。

编译libx265时,定位到其目录下,有个build文件夹,如下所示,支持的编译方式挺多
在这里插入图片描述

本人用的是vs2017编译,选择的是vc15-x86_64,注意vc15代表的不是vs2015,如下所示,本人vs2017的版本15.9.36,取版本的第一个字段15,所以vc15其实是vs2017,本人编译的是64位版本。
在这里插入图片描述
这里面有个make-solutions.bat,用于生成解决方案sln。但是先不要执行,首先打开cmd,
切换到目录D:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build,这也是本人vs2017的安装目录,
该目录下有如下文件
在这里插入图片描述
cmd中执行vcvars64.bat,初始化vs内部环境变量,执行后,诸如编译器cl.exe就能被命令行识别,然后再切换到libx265的build/vc15-x86_64目录,执行make-solutions.bat,然后会生成解决方案x265.sln,打开此解决方案,如下所示:
在这里插入图片描述
直接编译INSTALL工程,就会编译静态库和动态库,编译出的成果物如下所示:
在这里插入图片描述

头文件有两个:x265_config.h和x265.h,其中x265.h的内容是固定的,直接在源码文件中找就可以,而x265_config.h其实是由x265_config.h.in变化而来,不同编译器最终生成的也会不同。
在这里插入图片描述
读者可以看到这里面有两个x265_config.h,其中一个是由msys编译生成。

本人此处用msys也生成一遍,主要是vs编译器生成的不带x265.pc,本人最终在ffmpeg集成进libx265,需要x265.pc;其实这个文件也可以自己写。

本人的x265.pc内容如下:

prefix=/usr/local/x265
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: x265
Description: H.265/HEVC video encoder
Version: 3.5
Libs: -L${exec_prefix}/lib -lx265
Libs.private: 
Cflags: -I${prefix}/include 

很明显本人将x265的成果物拷贝到msys2目录下(本人拷贝的是动态库的引入库,不是静态库)。

然后打开msys2终端,设置x265的pkgconfigpath,如下所示:

export PKG_CONFIG_PATH=/usr/local/x265/lib/pkgconfig:$PKG_CONFIG_PATH

然后进入到ffmpeg的主目录,执行命令:

./configure --toolchain=msvc --arch=x86_64 --disable-debug --enable-gpl --enable-libfreetype --enable-libfontconfig --enable-libx264 --enable-libx265 --extra-cflags=-I/usr/local/x264/include --extra-ldflags='-LIBPATH:/usr/local/x264/lib' --prefix=/home/ffmpeg_x264_x265_vpx_freetype_fontconfig_static --enable-libvpx --enable-encoder=libvpx_vp8 --enable-encoder=libvpx_vp9 --enable-decoder=vp8 --enable-decoder=vp9 --enable-parser=vp8 --enable-parser=vp9

可以看到,本人此次编译ffmpeg,视频格式支持h264,h265,vp8,vp9。
生成makefile文件后,就可以进行编译了。

此处本人事先尝试了使用x265的静态库,但是在configure的时候报错,config.log显示大量的链接错误,本人只好用x265动态库的引入库,从而通过了configure,只是最终应用exe需要依赖libx265.dll,如果是静态库,则最终的成果物不需要libx265.dll,成果物会少一个文件。
关于这个问题,本人后续会研究下。

下面写一个录制桌面的例子:
在这里插入图片描述
其中文件CaptureScreen.h内容如下:

#ifndef _CCAPTURE_SCREEN_HH
#define _CCAPTURE_SCREEN_HH

#include<time.h>
#include <d3d9.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <windows.h>

#include <tchar.h>
#include <winbase.h>
#include <winreg.h>
#include <Strsafe.h>


//
// ---抓屏类----
//
class CCaptureScreen
{
public:
	CCaptureScreen(void);
	~CCaptureScreen(void);

public:
	/*-----------定义外部调用函数-----------*/
	int Init(int&, int&);//初始化
	BYTE* CaptureImage(); //抓取屏幕

private:
	/*-----------定义内部调用函数-----------*/
	void* CaptureScreenFrame(int, int, int, int);//抓屏
	HCURSOR FetchCursorHandle(); //获取鼠标光标

private:
	/*-----------定义私有变量-----------*/
	int m_width;
	int m_height;
	UINT   wLineLen;
	DWORD  dwSize;
	DWORD  wColSize;

	//设备句柄
	HDC hScreenDC;
	HDC hMemDC;
	//图像RGB内存缓存
	PRGBTRIPLE m_hdib;
	//位图头信息结构体
	BITMAPINFO pbi;

	HBITMAP hbm;
	//鼠标光标
	HCURSOR m_hSavedCursor;


};

#endif //--_CCAPTURE_SCREEN_HH

文件CaptureScreen.cpp内容如下:

//#include "stdafx.h"
#include "CaptureScreen.h"

CCaptureScreen::CCaptureScreen(void)
{
	m_hdib = NULL;
	m_hSavedCursor = NULL;
	hScreenDC = NULL;
	hMemDC = NULL;
	hbm = NULL;
	m_width = 1920;
	m_height = 1080;
	FetchCursorHandle();
}
//
// 释放资源
//
CCaptureScreen::~CCaptureScreen(void)
{
	DeleteObject(hbm);
	if (m_hdib){

		free(m_hdib);
		m_hdib = NULL;
	}
	if (hScreenDC){

		::ReleaseDC(NULL, hScreenDC);
	}
	if (hMemDC) {

		DeleteDC(hMemDC);
	}
	if (hbm)
	{
		DeleteObject(hbm);
	}
}

//
// 初始化
//
int CCaptureScreen::Init(int& src_VideoWidth, int& src_VideoHeight)
{
	hScreenDC = ::GetDC(GetDesktopWindow());
	if (hScreenDC == NULL) return 0;

	int m_nMaxxScreen = GetDeviceCaps(hScreenDC, HORZRES);
	int m_nMaxyScreen = GetDeviceCaps(hScreenDC, VERTRES);

	hMemDC = ::CreateCompatibleDC(hScreenDC);
	if (hMemDC == NULL) return 0;

	m_width = m_nMaxxScreen;
	m_height = m_nMaxyScreen;

	if (!m_hdib){
		m_hdib = (PRGBTRIPLE)malloc(m_width * m_height * 3);//24位图像大小
	}
	//位图头信息结构体
	pbi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	pbi.bmiHeader.biWidth = m_width;
	pbi.bmiHeader.biHeight = m_height;
	pbi.bmiHeader.biPlanes = 1;
	pbi.bmiHeader.biBitCount = 24;
	pbi.bmiHeader.biCompression = BI_RGB;

	src_VideoWidth = m_width;
	src_VideoHeight = m_height;

	hbm = CreateCompatibleBitmap(hScreenDC, m_width, m_height);
	SelectObject(hMemDC, hbm);

	wLineLen = ((m_width * 24 + 31) & 0xffffffe0) / 8;
	wColSize = sizeof(RGBQUAD)* ((24 <= 8) ? 1 << 24 : 0);
	dwSize = (DWORD)(UINT)wLineLen * (DWORD)(UINT)m_height;

	return 1;
}

//抓取屏幕数据
BYTE* CCaptureScreen::CaptureImage()
{

	VOID*  alpbi = CaptureScreenFrame(0, 0, m_width, m_height);
	return (BYTE*)(alpbi);
}

void* CCaptureScreen::CaptureScreenFrame(int left, int top, int width, int height)
{

	if (hbm == NULL || hMemDC == NULL || hScreenDC == NULL) return NULL;

	BitBlt(hMemDC, 0, 0, width, height, hScreenDC, left, top, SRCCOPY);
	/*-------------------------捕获鼠标-------------------------------*/
	{
		POINT xPoint;
		GetCursorPos(&xPoint);
		HCURSOR hcur = FetchCursorHandle();
		xPoint.x -= left;
		xPoint.y -= top;

		ICONINFO iconinfo;
		BOOL ret;
		ret = GetIconInfo(hcur, &iconinfo);
		if (ret){
			xPoint.x -= iconinfo.xHotspot;
			xPoint.y -= iconinfo.yHotspot;

			if (iconinfo.hbmMask) DeleteObject(iconinfo.hbmMask);
			if (iconinfo.hbmColor) DeleteObject(iconinfo.hbmColor);
		}
		/*画鼠标*/
		::DrawIcon(hMemDC, xPoint.x, xPoint.y, hcur);
	}
	//动态分配的内存
	PRGBTRIPLE hdib = m_hdib;
	if (!hdib)
		return hdib;

	GetDIBits(hMemDC, hbm, 0, m_height, hdib, (LPBITMAPINFO)&pbi, DIB_RGB_COLORS);
	return hdib;
}

//
// 获取窗体鼠标光标
//
HCURSOR CCaptureScreen::FetchCursorHandle()
{
	if (m_hSavedCursor == NULL)
	{
		m_hSavedCursor = GetCursor();
	}
	return m_hSavedCursor;
}

文件FfmpegVideoCaptureWithGdi.cpp内容如下:

// RecordingScreen.cpp : 定义控制台应用程序的入口点。
//

//#include "stdafx.h"
#include "CaptureScreen.h"
extern "C"
{
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil\time.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/imgutils.h>
#include <libavcodec/avcodec.h>
#include <libavdevice\avdevice.h>

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")


}
//#include <ipp.h>
#include <chrono>

//signed int Bgr2YuvI420(const BYTE* srcBgr, int image_width, int image_height, BYTE* dstYuvI420)
//{
//	IppStatus ipp_status;
//
//	int srcStep = image_width * 3;
//	int dstYStep = image_width;
//	int dstCbCrStep = image_width;
//	IppiSize roiSize = { image_width, image_height };
//
//	const Ipp8u* pSrc = (Ipp8u*)srcBgr;
//
//	Ipp8u *pDstY = (Ipp8u*)dstYuvI420;
//	Ipp8u *pDstU = (Ipp8u*)&dstYuvI420[image_width * image_height];
//	Ipp8u *pDstV = (Ipp8u*)&dstYuvI420[image_width * image_height * 5 / 4];
//	Ipp8u *pDst[3];
//	pDst[0] = pDstY;
//	pDst[1] = pDstU;
//	pDst[2] = pDstV;
//	int dstStep[3] = { image_width, image_width / 2, image_width / 2 };
//
//	ipp_status = ippiBGRToYCbCr420_8u_C3P3R(pSrc, srcStep, pDst, dstStep, roiSize);
//
//	return ipp_status;
//}


unsigned char clip_value(unsigned char x, unsigned char min_val, unsigned char  max_val) {
	if (x > max_val) {
		return max_val;
	}
	else if (x < min_val) {
		return min_val;
	}
	else {
		return x;
	}
}

//RGB to YUV420
bool RGB24_TO_YUV420(unsigned char *RgbBuf, int w, int h, unsigned char *yuvBuf)
{
	unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB;
	memset(yuvBuf, 0, w*h * 3 / 2);
	ptrY = yuvBuf;
	ptrU = yuvBuf + w * h;
	ptrV = ptrU + (w*h * 1 / 4);
	unsigned char y, u, v, r, g, b;
	for (int j = h - 1; j >= 0; j--) {
		ptrRGB = RgbBuf + w * j * 3;
		for (int i = 0; i < w; i++) {

			b = *(ptrRGB++);
			g = *(ptrRGB++);
			r = *(ptrRGB++);


			y = (unsigned char)((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
			u = (unsigned char)((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
			v = (unsigned char)((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
			*(ptrY++) = clip_value(y, 0, 255);
			if (j % 2 == 0 && i % 2 == 0) {
				*(ptrU++) = clip_value(u, 0, 255);
			}
			else {
				if (i % 2 == 0) {
					*(ptrV++) = clip_value(v, 0, 255);
				}
			}
		}
	}
	return true;
}


DWORD WINAPI ScreenCapThreadProc(LPVOID lpParam)
{
	CCaptureScreen* ccs = new CCaptureScreen();
	int width = 0;
	int height = 0;

	ccs->Init(width, height);

	AVFormatContext* avFormCtx_Out;
	AVCodecContext*  avCodecCtx_Out;
	AVCodec*  avCodec;
	AVStream* avStream;
	AVFrame* frame;
	AVPacket* packet;

	int frameRate = 10;
	int ret = 0;
	const char* filename = "out.mp4";

	ret = avformat_alloc_output_context2(&avFormCtx_Out, NULL, NULL, filename);
	if (ret < 0)
	{
		printf("Init avformat object is faild! \n");
		return 0;
	}

	//avCodec = (AVCodec *)avcodec_find_encoder(avFormCtx_Out->oformat->video_codec);
	avCodec = (AVCodec *)avcodec_find_encoder(AV_CODEC_ID_H265);
	
	if (!avCodec)
	{
		printf("Init avCodec object is faild! \n");
		return 0;
	}

	avCodecCtx_Out = avcodec_alloc_context3(avCodec);
	if (!avCodecCtx_Out)
	{
		printf("Init avCodecCtx_Out object is faild! \n");
		return 0;
	}
	avStream = avformat_new_stream(avFormCtx_Out, avCodec);
	if (!avStream)
	{
		printf("Init avStream object is faild! \n");
		return 0;
	}

	avCodecCtx_Out->flags |= AV_CODEC_FLAG_QSCALE;
	avCodecCtx_Out->bit_rate = 4000000;
	avCodecCtx_Out->rc_min_rate = 4000000;
	avCodecCtx_Out->rc_max_rate = 4000000;
	avCodecCtx_Out->bit_rate_tolerance = 4000000;
	avCodecCtx_Out->time_base.den = frameRate;
	avCodecCtx_Out->time_base.num = 1;

	avCodecCtx_Out->width = width;
	avCodecCtx_Out->height = height;
	//pH264Encoder->pCodecCtx->frame_number = 1;
	avCodecCtx_Out->gop_size = 12;
	avCodecCtx_Out->max_b_frames = 0;
	avCodecCtx_Out->thread_count = 4;
	avCodecCtx_Out->pix_fmt = AV_PIX_FMT_YUV420P;
	avCodecCtx_Out->codec_id = AV_CODEC_ID_H265;
	avCodecCtx_Out->codec_type = AVMEDIA_TYPE_VIDEO;

	av_opt_set(avCodecCtx_Out->priv_data, "b-pyramid", "none", 0);
	av_opt_set(avCodecCtx_Out->priv_data, "preset", "superfast", 0);
	av_opt_set(avCodecCtx_Out->priv_data, "tune", "zerolatency", 0);

	if (avFormCtx_Out->oformat->flags & AVFMT_GLOBALHEADER)
		avCodecCtx_Out->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

	ret = avcodec_open2(avCodecCtx_Out, avCodec, NULL);
	if (ret < 0)
	{
		printf("Open avcodec is faild! \n");
		return 0;
	}

	avcodec_parameters_from_context(avStream->codecpar, avCodecCtx_Out);
	if (!(avFormCtx_Out->oformat->flags & AVFMT_NOFILE))
	{
		ret = avio_open(&avFormCtx_Out->pb, filename, AVIO_FLAG_WRITE);
		if (ret < 0)
		{
			printf("Open file is faild! \n");
			return 0;
		}
	}
	ret = avformat_write_header(avFormCtx_Out, NULL);
	if (ret < 0)
	{
		printf("write header is faild! \n");
		return 0;
	}

	frame = av_frame_alloc();
	if (!frame)
	{
		printf("Init frame is faild! \n");
		return 0;
	}
	frame->format = AV_PIX_FMT_YUV420P;
	frame->width = width;
	frame->height = height;

	LONG64 frameSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, 1920, 1080, 1);
	BYTE* outbuffer = new BYTE[frameSize];

	ret = av_image_fill_arrays(frame->data,
		frame->linesize,
		outbuffer,
		AV_PIX_FMT_YUV420P,
		1920,
		1080, 1);

	if (ret < 0)
	{
		printf("av_image_fill_arrays is faild! \n");
		return 0;
	}
	packet = av_packet_alloc();
	//av_init_packet(packet);
	if (!packet)
	{
		printf("packet is faild! \n");
		return 0;
	}

	int frameNumber = 0;
	int got_packet = 0;

	DWORD dwBeginTime = ::GetTickCount();
	for (;;)
	{
		BYTE* frameimage = ccs->CaptureImage();

		RGB24_TO_YUV420(frameimage, width, height, outbuffer);

		DWORD dwCurrentTime2 = ::GetTickCount();
		DWORD dwLastTime = dwCurrentTime2 - dwBeginTime;

		frame->pkt_dts = frame->pts = av_rescale_q_rnd(frameNumber, avCodecCtx_Out->time_base, avStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		frame->pkt_duration = 0;
		frame->pkt_pos = -1;
		

		//frame->pkt_dts = frame->pts = av_rescale_q_rnd(frameNumber, avCodecCtx_Out->time_base, avStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		//frame->pkt_duration = 0;
		//frame->pkt_pos = -1;

		ret = avcodec_send_frame(avCodecCtx_Out, frame);
		if (ret < 0)
			continue;

		ret = avcodec_receive_packet(avCodecCtx_Out, packet);
		if (ret < 0)
			continue;

		static DWORD dwInitTime = ::GetTickCount();
		if (packet->size > 0)
		{
			//av_packet_rescale_ts(packet, avCodecCtx_Out->time_base, avStream->time_base);
			av_write_frame(avFormCtx_Out, packet);
			frameNumber++;
			printf("录入第%d帧....\n", frameNumber);
		}

		DWORD dwCurrentTime = ::GetTickCount();
		if (dwCurrentTime - dwInitTime > 30 * 1000)
		{
			break;
		}

		int dwPassedMillSeconds = dwCurrentTime - dwBeginTime;
		int dwDiff = frameNumber * 100 - dwPassedMillSeconds;
		if (dwDiff > 0)
		{
			Sleep(dwDiff);
		}
	}
	av_write_trailer(avFormCtx_Out);
	avformat_free_context(avFormCtx_Out);
	avcodec_close(avCodecCtx_Out);
	avcodec_free_context(&avCodecCtx_Out);
	av_free(avCodec);
	av_packet_free(&packet);
	av_frame_free(&frame);
	return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
	//av_register_all();
	//avformat_network_init();
	avdevice_register_all();


	HANDLE hThread = CreateThread(NULL, 0, ScreenCapThreadProc, 0, 0, NULL);
	WaitForSingleObject(hThread, INFINITE);
	return 0;
}






录制的文件有30秒,文件格式如下
在这里插入图片描述
这里的hevc就是h265。

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

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

相关文章

java基础 网络编程

网络编程概念&#xff1a; 让程序可以和网络上的其他设备中的程序进行数据交互。 网络通信基本模式&#xff1a; CS&#xff1a;Client-Server 自己写客户端和服务器交流 BS&#xff1a;Browser/Server 通过浏览器和服务器交流 实现网络编程关键的三要素…

python中的函数与变量

一、函数python中函数的基本格式则为:def函数名参数名函数体返回&#xff0c;python作为一门面向对象的语言&#xff0c;同样可分为类函数、实例函数。 # 定义一个函数 def add(x, y):"""函数的说明:param x: 参数x的作用:param y: 参数y的作用:return: 函数返…

碱性环境吸钯树脂技术

汞和贵金属的选择性去除回收离子交换树脂 Tulsimer CH-95S 是一款为了从工业废水中去除回收汞和贵金属而开发的螯合树脂。 Tulsimer CH-95S是一款拥有聚乙烯异硫脲官能基的大孔树脂&#xff0c;这种树脂对汞有的选择性。它也选择其他的贵金属&#xff0c;如黄金&#xff0c;铂…

消息收发弹性——生产集群如何解决大促场景消息收发的弹性降本诉求

作者&#xff1a;宸罡 产品介绍—什么是消息收发弹性 大家好&#xff0c;我是来自阿里云云原生消息团队的赖福智&#xff0c;花名宸罡&#xff0c;今天来给大家分享下阿里云 RocketMQ5.0 实例的消息弹性收发功能&#xff0c;并且通过该功能生产集群是如果解决大促场景消息收发…

JS in CSS:一键支持响应式布局

前言 如今网速不再成为适配移动端时选择响应式设计的限制因素&#xff0c;在资源充足的条件下&#xff0c;针对各端各自设计应用界面能达到应用最佳用户体验&#xff0c;毕竟不同类型的设备交互体验是不同的&#xff0c;但在团队前端资源拮据时&#xff0c;相比无脑自适应&…

基于Java+jquery+SpringMVC校园网站平台设计和实现

基于JavajquerySpringMVC校园网站平台设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联…

临时白名单

临时白名单介绍 相关常量 临时白名单列表介绍 前两个临时白名单可以豁免后台启动Service、豁免uid后台1min后进入idle状态等&#xff0c;最后一个临时白名单可以后台启动FGS。 // 由于高优先级消息而暂时允许逃避后台检查的一组应用程序 ID&#xff0c;短信/彩信 Composite…

【Vue路由】路由守卫、生命周期钩子、路由器工作模式

文章目录生命周期钩子案例实现总结路由守卫全局路由守卫独享守卫组件内守卫总结路由器的两种工作模式总结生命周期钩子 我们在News组件列表中的第一行加一个渐变文字。同时原来的路由缓存功能也要保存。 案例分析&#xff1a; 我们实现这个渐变的效果&#xff0c;是使用周期定…

Go select底层原理

在对Channel的读写方式上&#xff0c;除了我们通用的读 i <- ch, i, ok <- ch&#xff0c;写 ch <- 1 这种阻塞访问方式&#xff0c;还有select关键字提供的非阻塞访问方式。 在日常开发中&#xff0c;select语句还是会经常用到的。可能是channel普通读写的使用频率比…

基于Node.js和vue的博客系统的设计与实现

摘要随着互联网技术的高速发展&#xff0c;人们生活的各方面都受到互联网技术的影响。现在人们可以通过互联网技术就能实现不出家门就可以在线发布博客文章&#xff0c;简单、快捷的方便了人们的日常生活。同样的&#xff0c;在人们的工作生活中&#xff0c;也需要互联网技术来…

【Java寒假打卡】Java基础-日期类对象

【Java寒假打卡】Java基础-日期类对象Date概述Date类常用成员方法SimpleDateFormat案例:秒杀活动案例&#xff1a;在当前时间加上一天时间JDK8新增日期类获取时间中的一个值LocalDateTime转换方法LocalDateTime格式化和解析LocalDateTime 增加或者减少时间的方法修改时间的方法…

【JAVA程序设计】(C00099)基于SpringBoot的外卖订餐小程序(原生开发)

基于SpringBoot的外卖订餐小程序&#xff08;原生开发&#xff09;项目简介项目获取开发环境项目技术运行截图项目简介 基于SpringBootvue开发的原生外卖点餐微信小程序&#xff0c;包括用户小程序登录以及网页端的商家登录。本系统分为三个权限&#xff1a;商家、用户和游客&…

第七章.机器学习 Scikit-Learn—最小二乘法回归,岭回归,支持向量机,K_means聚类算法

第七章.机器学习 Scikit-Learn 7.1 Scikit-Learn简介 Scikit-Learn简称(SKlearn)是Python的第三方模块&#xff0c;是机器学习领域当中知名的Python模块之一&#xff0c;对常用的机器学习算法进行了封装&#xff0c;包括回归(Regression)&#xff0c;降维(Dimensionality Redu…

地质灾害监测预警系统构成,功能,监测设备介绍

平升电子地质灾害监测预警系统&#xff0c;应用平升物联网遥测终端机、专业测量仪器和传感设备、预警广播设备、地质灾害监测预警平台&#xff0c;基于4G/5G/NB-IoT/LoRa/光纤/北斗卫星通信网络&#xff0c;实时在线监测地质灾害隐患点的地表位移、地表裂缝、深部位移、降雨量、…

Simulink-过零检测与代数环

过零检测过零检测即通过Simulink为模块注册若干过零函数&#xff0c;当模块变化趋势剧烈时&#xff0c;过零函数将会发生符号变化。每个采样点仿真结束时&#xff0c;Simulink检测过零函数是否有符号变化&#xff0c;如果检测到过零点&#xff0c;则Simulink将在前一个采样点和…

院内导航方案怎么样,低成本的智慧医院室内导航一站式解决方案

很多智慧医院的方案里都提到了院内导航&#xff0c;它俨然已经成为智慧医院套餐中的“招牌菜”&#xff0c;甚至被打上了“导航神器”的绰号&#xff0c;其中电子地图作为大家最喜闻乐见的高效应用形式&#xff0c;可以高效的为病患提供导医服务&#xff0c;实现院内导航功能&a…

集群多机ROS通信中间件:swarm_ros_bridge

最近写了一个无线网络环境下&#xff08;比如WIFI&#xff09;多机ROS通信的项目swarm_ros_bridge&#xff1a; https://gitee.com/shu-peixuan/swarm_ros_bridge A lightweight middle interface that enables specified ROS message transmission among swarm robots throu…

国内出海企业常见的跨境网络问题分析及解决方案

经济全球化趋势发展得如火如荼&#xff0c;越来越多的中国企业走出国门&#xff0c;兴起包括跨境电商、虚拟商品、游戏出海等新贸易形式。但在业务开拓过程中&#xff0c;由于远距离传输的特殊性&#xff0c;出海企业经常面临网络传输慢、不稳定、延迟、掉线等网络问题&#xf…

0基础如何开始学习计算机知识?

一、计算机的基本操作 计算机中只有文件和文件夹 计算机中&#xff0c;只有两样东西&#xff0c;文件和文件夹。 文件夹&#xff1a;本身不存储数据内容。文件夹是用来组织和管理文件的。 文件&#xff1a; 所有的txt文本文档&#xff0c;音乐&#xff0c;视频&#xff0c;图…

2022年国外LEAD收入情况

欢迎关注勤于奋每天12点准时更新国外LEAD相关技术这个收入情况&#xff0c;最喜欢关心&#xff0c;最喜欢看的人应该是新手和观望的人最想知道的&#xff0c;LEAD收入只要操作了&#xff0c;赚钱肯定是没问题&#xff0c;我一直这样说&#xff0c;而且我公众号叫勤于奋&#xf…