ffmpeg vs2017录制vp9格式的桌面视频

news2024/9/20 14:39:17

ffmpeg本身不支持vp8,vp9;若要支持,则需要自己事先编译好vpx库,然后在ffmpeg中显式支持vpx库。

windows下采用mingw编译器编译vpx;本人采取的是MSYS2,并且本人编译vpx和ffmpeg时,编译的都是静态库,故而在编译vpx和ffmpeg的时候,需要指定编译器。

在MSYS2的安装目录下,找到文件,msys2_shell.cmd,打开,在第一行加入vs2017环境变量的调用,如下所示:
在这里插入图片描述

call "D:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat"

然后启动msys2,进入到libvpx的解压缩目录,本人采取的版本是libvpx-1.12.0,首先执行./configure --help,可以看到支持的target如下:
在这里插入图片描述
本人是vs2017,64位静态库编译,选择的target是x86_64-win64-vs15,注意,这地方不能选择x86_64-win64-vs17,可以到vs2017中查看版本信息,如下所示,版本中的第一个字段值是15.
在这里插入图片描述
然后执行./configure --target=x86_64-win64-vs15 --enable-static-msvcrt,生成Makefile文件,接着执行make和make install。
编译的成果物目录如下,有Debug和Release
在这里插入图片描述
很遗憾,本人未能找到只编译Release成果物的配置方式,导致编译时间比较长。
make install的时候,只会安装Release的库。

接着是编译配置ffmpeg了,命令如下:

./configure --toolchain=msvc --arch=x86_64 --disable-debug --enable-gpl --enable-libfreetype --enable-libfontconfig --enable-libx264 --extra-cflags=-I/usr/local/x264/include --extra-ldflags='-LIBPATH:/usr/local/x264/lib' --prefix=/home/ffmpeg_x264_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

最后本人写了一个例子,录制桌面视频,编码格式是VP9。

在这里插入图片描述

其中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;
}

extern const AVOutputFormat ff_mp4_muxer;

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";

	/*
	AVOutputFormat ff_mp4_muxer = {
	.name = "mp4",
	.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
	.mime_type = "video/mp4",
	.extensions = "mp4",
	.priv_data_size = sizeof(MOVMuxContext),
	.audio_codec = AV_CODEC_ID_AAC,
	.video_codec = CONFIG_LIBX264_ENCODER ?
						 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
	.init = mov_init,
	.write_header = mov_write_header,
	.write_packet = mov_write_packet,
	.write_trailer = mov_write_trailer,
	.deinit = mov_free,
	.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
	.codec_tag = mp4_codec_tags_list,
	.check_bitstream = mov_check_bitstream,
	.priv_class = &mp4_muxer_class,
	};
	*/
	/*AVOutputFormat ff_mp4_muxer;
	ff_mp4_muxer.video_codec = AV_CODEC_ID_VP9;
	ff_mp4_muxer.audio_codec = AV_CODEC_ID_AAC;
	ff_mp4_muxer.name = "mp4";
	ff_mp4_muxer.long_name = "MP4 (MPEG-4 Part 14)";
	ff_mp4_muxer.extensions = "mp4";*/


	ret = avformat_alloc_output_context2(&avFormCtx_Out, NULL, NULL, filename);
	if (ret < 0)
	{
		printf("Init avformat object is faild! \n");
		return 0;
	}
	//AVOutputFormat * poformat = (AVOutputFormat *)avFormCtx_Out->oformat;
	//poformat->video_codec = AV_CODEC_ID_VP9;

	//avCodec = (AVCodec *)avcodec_find_encoder(avFormCtx_Out->oformat->video_codec);
	avCodec = (AVCodec *)avcodec_find_encoder(AV_CODEC_ID_VP9);
	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_VP9;
	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 > 60 * 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;
}






最后出来的是VP9格式的视频。

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

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

相关文章

【云原生】在Ubuntu18/20上部署Kubernetes/k8s集群详细教程——亲测可用!!网上其他教程均有问题!

在Ubuntu18/20上部署Kubernetes/k8s详细教程一、设置Docker二、安装Kubernetes第 1 步&#xff1a;添加Kubernetes签名密钥第 2 步&#xff1a;添加软件存储库第 3 步&#xff1a;Kubernetes 安装工具三、部署 Kubernetes步骤 1&#xff1a;准备 Kubernetes 部署步骤 2&#xf…

怎么找回笔记本的数据?笔记本数据恢复,6个教程

“我不小心删除了笔记本电脑里面的重要数据&#xff0c;请问被误删的数据还可以恢复吗&#xff1f;如果可以恢复&#xff0c;我应该怎么恢复笔记本里面的数据&#xff1f;” 很多人在使用笔记本电脑的时候&#xff0c;经常误删一些数据&#xff0c;有时是工作文档&#xff0c;…

我是如何将同事的代码改成DDD风格的

DDD是领域驱动设计的简写。前段时间听群友说行业里少有DDD的代码案例&#xff0c;进而对DDD没有一个感性的认识。我想这是行业里普遍存在的现象吧。所以&#xff0c;就有了写此文的想法。文章标题说的是“同事的代码”&#xff0c;其实只是为了让此文更具传播&#xff0c;没别的…

组件的生命周期、vue2中使用axios、插槽

目录 一、组件的生命周期 1、什么是组件的生命周期 2、生命周期函数 3、生命周期的阶段划分 4、钩子函数 5、keep-alive组件 6、生命周期函数&#xff1a; 二、vue2中使用axios 1、axios&#xff1a;是一个基于Promise的网络请求库。既可以在node.js&#xff08;服务器…

【MySQL】1. 了解数据库以及MySQL安装

了解数据库和SQL什么是数据库为什么使用数据库MySQL下载,安装,配置客户端连接MySQL方法一方法二SQLSQL分类SQL的基本规则命名规则最后大家好, 我是路不停_。 上学期学校学习了MySQL之后,课后也没有做很多总结,加上课时紧凑,后续考试也是考前草草备考了一下. 最近读了本MySQL必知…

C 程序设计教程(03)—— C 语言的数据类型(一):基本数据类型

C 程序设计教程&#xff08;03&#xff09;—— C 语言的数据类型&#xff08;一&#xff09;&#xff1a;基本数据类型 一、数据类型简介 C 语言提供了丰富的数据类型&#xff0c;每一个常量和变量必须属于某一种数据类型。C 语言中的数据类型如下&#xff1a; &#xff08…

基础数学(八)——期末考试复习

文章目录考试要求考试内容简单复习插值拟合和回归数值积分直接法迭代法非线性方程求根微分方程数值解去年考题第一题&#xff0c;插值&#xff08;12分&#xff09;第二题&#xff0c;回归和拟合第三题&#xff0c;数值积分第四题&#xff0c;线性方程组求解第五题&#xff0c;…

MGRE实验配置(华为)

华为ENSP的MGRE实验&#xff1a; 建立好拓扑图 之后就是对各个路由器的配置&#xff1a; R2配置&#xff1a; int s3/0/0 link-protocol hdlc 更改接口为hdlc认证 ip address 12.1.1.2 24 int lo0 ip add 2.2.2.2 24 int s3/0/1 [r2-Serial3/0/1]ip address 23.1.1.2 24 [r2-Se…

【ML】 基本概念

ML 基本概念1. different types of functions2. how to find the function - training data3. unseen during training4. Back to ML Framework4.1 Step1: function with unknown4.2 Step2: define loss from training data4.3 step3: optimization4.4 其他4.4.1 Sigmoid → Re…

基础算法(五)——双指针算法

双指针算法 介绍 双指针算法分为两大类&#xff1a; 两个指针指向两个不同序列&#xff0c;用两个指针维护某一种逻辑&#xff0c;例如归并排序 两个指针指向一个序列&#xff0c;即用两个指针维护一段区间&#xff0c;例如快排 核心思想&#xff1a; 若能证明出题目存在…

Linux工具学习之【vim】

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f38a;每篇一句&#xff1a; 图片来源 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 Whatever is worth doing is worth doing well. 任何值得去做的事情&#xff0…

springboot垃圾分类查询管理系统

1.介绍 垃圾分类查询管理系统&#xff0c;对不懂的垃圾进行查询进行分类并可以预约上门回收垃圾。 让用户自己分类垃圾&#xff0c; 按国家标准自己分类&#xff0c; 然后在网上提交订单&#xff0c; 专门有人负责回收&#xff0c; 统一回收到垃圾处理站&#xff0c; 然后工人…

Renesas 3 --烧写

1.烧录Boot程序 1.1&#xff0c;连接RESET_OUT, TOOL0, GND到板子。 1.2&#xff0c;上电后烧录器上指示灯亮&#xff08;假如不亮&#xff0c;重新上电烧录器&#xff09; 1.3&#xff0c;用Renesas flash programmer来烧写软件&#xff08;新建项目&#xff0c;然后保存项目…

RAW怎么转为JPG?这些转换技巧值得收藏

相信大多数的人&#xff0c;出去外面游玩时都喜欢使用相机来拍照&#xff0c;但是大多数相机拍出来的照片都是RAW格式&#xff0c;图片传到电脑时&#xff0c;会因为格式的不兼容而导致无法查看&#xff0c;这个时候我们就需要把图片的格式进行转换&#xff0c;例如我们将其转换…

Day850.GuardedSuspension模式 -Java 性能调优实战

GuardedSuspension模式 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于GuardedSuspension模式的内容。 小灰工作中遇到一个问题&#xff0c;开发了一个 Web 项目&#xff1a;Web 版的文件浏览器&#xff0c;通过它用户可以在浏览器里查看服务器上的目录和文件。 这…

(原创)Flow数据流的使用

前言 这篇文章主要介绍Flow的一些基础使用方法 同时介绍如何用Flow请求网络数据 下面开始&#xff01; 什么是Flow Flow翻译过来&#xff0c;是“流”的意思 举例说明&#xff0c;在大自然中&#xff0c;常见的如水流 是从高往低流动的 那么在计算机世界里&#xff0c;所谓的…

loss盘点: asl loss (Asymmetric Loss) 代码解析详细版

1. BCE公式部分 可以简单浏览下这篇博客的文章&#xff1a; https://blog.csdn.net/qq_14845119/article/details/114121003 这是多分类 经典 BCELossBCELossBCELoss 公式 L−yL−(1−y)L−L -y L_{} - (1-y) L_{-} L−yL​−(1−y)L−​ 其中&#xff0c;L/−L_{/-}L/−​…

Docker保姆级学习教程

文章目录1、什么是Docker1.1、容器技术1.2、容器与虚拟机比较1.3、Docker特点1、更高效的利用系统资源2、更快速的启动时间3、一致的运行环境4、持续支付和部署5、更轻松的迁移6、更轻松的维护和扩展2、Docker组件学习2.1、Docker客户端和服务器2.2、Docker镜像2.3、Registry&a…

奇怪的知识——Windows下怎么修改进程的名称?

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;无尽的折腾后&#xff0c;终于又回到…

element-plus的form表单form-item的prop怎么写才能正确校验,实现逻辑是怎么样的?

不管是element-plus还是上一个版本的element-ui&#xff0c;都是一个使用很广泛的基于csshtmljs的ui组件库&#xff0c;它的form表单自带强大的校验功能&#xff0c;form-item的prop怎么写才正确&#xff0c;实现逻辑是怎么样的&#xff1f;element-plus的form表单的model、for…