文本转语音-音画适时推送rtsp并播放

文本语音 rtsp适时播放叫号系统的底层逻辑


发布Linux, unix socket 和window win32做为音频源的 python10下的(ffmpeg version 7.1) 可运行版本.

这两天在弄这个,前2篇是通过虚拟声卡,达到了最简单的一个逻辑,播放文本就从声卡发声,不播无所谓,自动忙音。 那个工作在windows平台,
而今天的这个相似功能的代码是mac os,理论支持windows,和linux,依赖ffmpeg和xiu(一个rust流服务器)的rtsp服务。
今天的难点有点多

  1. asyncio的任务 async def _tts_worker(self, text: str) 运行中有各种错误, engine runAndWait是不行的。 内部有它的event loop。所以init和endLoop,是暂时找到的解决办法。同时经历了,这个,和调用 ffmpeg 外部指令,并直接获取- 代表的stdout。 会遇到各种问题。做了捕获和处理。但是查找的时候,不是太容易。
  2. self._start_ffmpeg() 他需要, create socket 或pipe完成以后,才能运行。 调试我都手工在外部启动。 作用就是,输出到rtsp服务器,以备播放。
  3. input handle,等都是ai生成的,因为有好多种循环,这是比较省心在。
  4. 最紧急隐蔽在是, async def _heartbeat(self) 他需要计算播放静音的时间,长了不行,短了不行。 这个最初在测试代码,就几个函数。然后AI,生成了三个theading的版本,两个Queue。 然后转到了异步版本,明显快了很多。
  5. 在windows上使用win32pipen可以达到unix socket的效果很相似, 记得还有FIFO是linux专用的,当然还有stdin,和stdout。对于ffmpeg,这是一些程序内部的传送机制
  6. rtsp是需要一个后台的服务的,xiu是开源的rust项目,可以使。另外window推荐metamtx,双击运行,什么也不管。
    在这里插入图片描述

音画同步应该是另个问题了,几天前,鼓捣了一下图片。让编辑后的,马上 在视频中显示。 这个另外一个话题了。做的这些就为了,让报号和点单,有个界面。

ffmpeg -re -framerate 30 -f image2 -loop 1 -i "image1.jpg" -c:v libx264 -preset ultrafast -tune zerolatency -pix_fmt rgba  -f rtsp -rtsp_transport tcp rtsp://localhost:8554/live

合并的代码,就当成剩下的作业,有空再来做。

对于刚接触的,最好是慢慢和AI调试着来,一些功能就做出来。

启动
接收text
FIFOunix..
同步语音传输
语音 推送
文本转语音
rtsp流服务器

语音推送使用ffmpeg独立进程,实现了前后中断后自动重启。

程序主体

可独立运行,也可以结合ffmg管理推送进程

  1. macos ,理论Linux适用,单文件可执行
    main.py
import asyncio
import struct
import pyttsx3
import tempfile
import os
import socket
from aioconsole import ainput
from contextlib import suppress
from typing import Optionalclass AsyncTTSController:def __init__(self):# 使用Unix域套接字self.socket_path = "/tmp/tts_audio.sock"self.server_socket: Optional[socket.socket] = Noneself.client_socket: Optional[socket.socket] = None# 进程控制self.ffmpeg_process: Optional[asyncio.subprocess.Process] = Noneself.running = False# TTS引擎self.engine = pyttsx3.init()self.engine.setProperty('rate', 180)self.engine.setProperty('volume', 1.0)# 音频参数self.sample_rate = 24000self.channels = 1self.bits_per_sample = 16self.silence = self._generate_silence(0.2)self.wav_header = self._generate_wav_header()# 状态管理self.connection_active = Falseself.last_heartbeat = 0.0self.heartbeat_interval = 2.0self.sending_audio = 0def _generate_wav_header(self) -> bytes:"""生成WAV文件头"""byte_rate = self.sample_rate * self.channels * self.bits_per_sample // 8block_align = self.channels * self.bits_per_sample // 8return struct.pack('<4sI4s4sIHHIIHH4sI',b'RIFF', 36, b'WAVE', b'fmt ', 16, 1, self.channels,self.sample_rate, byte_rate, block_align, self.bits_per_sample,b'data', 0)def _generate_silence(self, duration: float) -> bytes:"""生成静音数据"""samples = int(self.sample_rate * duration)return bytes(samples * self.channels * (self.bits_per_sample // 8))async def _async_create_socket(self) -> None:"""创建Unix域套接字"""with suppress(Exception):if os.path.exists(self.socket_path):os.unlink(self.socket_path)self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)self.server_socket.setblocking(False)self.server_socket.bind(self.socket_path)self.server_socket.listen(1)loop = asyncio.get_running_loop()while self.running and not self.connection_active:try:self.client_socket, _ = await loop.sock_accept(self.server_socket)self.connection_active = Trueprint("客户端已连接")await loop.sock_sendall(self.client_socket, self.wav_header)except (BlockingIOError, InterruptedError):await asyncio.sleep(0.1)except Exception as e:print(f"连接错误: {str(e)}")self.connection_active = Falseawait asyncio.sleep(1)async def _start_ffmpeg(self) -> None:"""启动FFmpeg进程"""with suppress(Exception):if self.ffmpeg_process:self.ffmpeg_process.terminate()await self.ffmpeg_process.wait()socketid='unix:'+self.socket_pathself.ffmpeg_process = await asyncio.create_subprocess_exec('ffmpeg','-f', 's16le','-ar', str(self.sample_rate),'-ac', str(self.channels),'-i', socketid,  # 修改输入源为套接字路径'-c:a', 'aac','-f', 'rtsp','-rtsp_transport', 'tcp','rtsp://localhost:8554/mystream',stdout=asyncio.subprocess.DEVNULL,stdin=asyncio.subprocess.DEVNULL,stderr=asyncio.subprocess.PIPE)asyncio.create_task(self._monitor_ffmpeg_errors())async def _monitor_ffmpeg_errors(self) -> None:"""监控FFmpeg错误输出"""while self.running and self.ffmpeg_process:line = await self.ffmpeg_process.stderr.readline()if not line:break#   print(f"[FFmpeg Error] {line.decode().strip()}")async def _async_write_socket(self, data: bytes) -> None:"""安全写入套接字"""try:if self.client_socket and self.connection_active:loop = asyncio.get_running_loop()await loop.sock_sendall(self.client_socket, data)except (BrokenPipeError, ConnectionResetError):print("连接已断开,尝试重连...")await self._reconnect_pipeline()except Exception as e:print(f"写入错误: {str(e)}")self.connection_active = Falseasync def _reconnect_pipeline(self) -> None:"""完整重连流程"""print("启动重连流程...")self.connection_active = Falseif self.client_socket:self.client_socket.close()task1=asyncio.create_task(self._async_create_socket()),task2=asyncio.create_task( self._start_ffmpeg()),    await task2await task1# await asyncio.gather(task1, task2)#await self._async_create_socket()#await self._start_ffmpeg()# 剩余的heartbeat、tts_worker、input_handler等方法保持相同...async def stop(self) -> None:"""安全关闭"""self.running = Falsewith suppress(Exception):if self.ffmpeg_process:self.ffmpeg_process.terminate()await self.ffmpeg_process.wait()if self.client_socket:self.client_socket.close()if self.server_socket:self.server_socket.close()if os.path.exists(self.socket_path):os.unlink(self.socket_path)print("所有资源已释放")async def _heartbeat(self) -> None:"""心跳维持机制"""while self.running:if self.connection_active :for i in range(10):if   self.sending_audio<0:await self._async_write_socket(self.silence)else :self.sending_audio-= 2await asyncio.sleep(0.2)   #     print(self.sending_audio,"slend")#  await asyncio.sleep(self.heartbeat_interval)else:await asyncio.sleep(0.5)def _sync_tts(self,text,tmp_filename):eng=pyttsx3.init()#  eng.say(text)eng.save_to_file(text, 'temp3.wav')eng.runAndWait()eng.endLoop()async def _tts_worker(self, text: str) -> None:"""异步TTS处理核心"""tmp_filename = None#with open('audio1.raw','rb') as chunkf:# data=chunkf.read()# secdd=len(data)/48000# self.sending_audio=int(secdd*10) # await self._async_write_socket(data)# #await asyncio.sleep(secdd)# print (secdd,len(data) )   # 创建临时文件with tempfile.NamedTemporaryFile(delete=False) as tmp:tmp_filename = tmp.name# # 同步TTS操作转异步执行loop = asyncio.get_running_loop()await loop.run_in_executor(None, self._sync_tts, *(text, 'temp3.wav',))# 转换音频格式# await asyncio.sleep(1.3)# self._sync_tts(text,tmp_filename)try: proc = await asyncio.create_subprocess_exec('ffmpeg','-hide_banner','-loglevel', 'error','-y','-i', 'temp3.wav',       # 输入文件路径'-f', 's16le',            # 强制输出格式为PCM s16le'-acodec', 'pcm_s16le',   # 明确指定音频编解码器 👈 关键修复'-ar', str(self.sample_rate),'-ac', str(self.channels),'-',                     # 输出到标准输出stdout=asyncio.subprocess.PIPE
)# 流式发送音频数据sum=0while chunk := await proc.stdout.read(4096):sum+=len(chunk)await self._async_write_socket(chunk)self.sending_audio=int(sum*10/48000) print("write data x0.1s:",self.sending_audio)finally:if tmp_filename and os.path.exists(tmp_filename):1#  os.unlink(tmp_filename)async def _input_handler(self) -> None:"""异步输入处理"""while self.running:try:text = await ainput("请输入文本(输入q退出): ")if text.lower() == 'q':self.running = Falsebreakif text.strip():await self._tts_worker(text)except Exception as e:print(f"输入错误: {str(e)}")async def run(self) -> None:"""主运行循环"""self.running = True# #await  self._start_ffmpeg()tasks = [asyncio.create_task(self._async_create_socket()),asyncio.create_task( self._start_ffmpeg()),asyncio.create_task(self._input_handler()),asyncio.create_task(self._heartbeat()),]await asyncio.gather(*tasks)# 以下保持不变...
if __name__ == "__main__":controller = AsyncTTSController()try:asyncio.run(controller.run())except KeyboardInterrupt:asyncio.run(controller.stop())
"""
ffmpeg -y -i temp.wav -f s16le -acodec pcm_s16le  -ar 24000  -ac 1   audio.raw
ffmpeg  -ar 24000 -ac 1 -f s16le  -i unix:/tmp/tts_audio.sock -f rtsp  rtsp://localhost:8554/mystream
"""
  1. window10系统python10 可运行版本
    主要让deepseek,执行了,socket 到 win32pipen的替换.因为本来就是换过去的.这一块的代码完全没有手工介入. 唯一改的是注释eng.endLoop(),并不用每次init() ,应改是pyttsx3的一个跨平台特性. ,异步的win32下支持稳定.
    def _sync_tts(self, text, tmp_filename):eng = self.engine  #pyttsx3.init()eng.save_to_file(text, 'temp3.wav')eng.runAndWait()#  eng.endLoop()

main-win.py

import asyncio
import struct
import pyttsx3
import tempfile
import os
from aioconsole import ainput
from contextlib import suppress
from typing import Optional
import win32pipe
import win32file
import pywintypesclass AsyncTTSController:def __init__(self):# 使用Windows命名管道self.pipe_name = r'\\.\pipe\tts_audio_pipe'self.pipe_handle = None# 进程控制self.ffmpeg_process: Optional[asyncio.subprocess.Process] = Noneself.running = False# TTS引擎self.engine = pyttsx3.init()self.engine.setProperty('rate', 180)self.engine.setProperty('volume', 1.0)# 音频参数self.sample_rate = 24000self.channels = 1self.bits_per_sample = 16self.silence = self._generate_silence(0.2)self.wav_header = self._generate_wav_header()# 状态管理self.connection_active = Falseself.last_heartbeat = 0.0self.heartbeat_interval = 2.0self.sending_audio = 0def _generate_wav_header(self) -> bytes:"""生成WAV文件头"""byte_rate = self.sample_rate * self.channels * self.bits_per_sample // 8block_align = self.channels * self.bits_per_sample // 8return struct.pack('<4sI4s4sIHHIIHH4sI',b'RIFF', 36, b'WAVE', b'fmt ', 16, 1, self.channels,self.sample_rate, byte_rate, block_align, self.bits_per_sample,b'data', 0)def _generate_silence(self, duration: float) -> bytes:"""生成静音数据"""samples = int(self.sample_rate * duration)return bytes(samples * self.channels * (self.bits_per_sample // 8))async def _async_create_pipe(self) -> None:"""创建命名管道"""while self.running and not self.connection_active:try:# 创建命名管道self.pipe_handle = win32pipe.CreateNamedPipe(self.pipe_name,win32pipe.PIPE_ACCESS_DUPLEX,win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_READMODE_BYTE | win32pipe.PIPE_WAIT,1,  # 最大实例数65536, 65536,  # 输入输出缓冲区大小0,  # 默认超时None  # 安全属性)# 异步等待连接loop = asyncio.get_running_loop()await loop.run_in_executor(None, win32pipe.ConnectNamedPipe, self.pipe_handle, None)self.connection_active = Trueprint("客户端已连接")await self._async_write_socket(self.wav_header)except pywintypes.error as e:if e.winerror == 536:  # ERROR_PIPE_CONNECTEDself.connection_active = Trueprint("客户端已连接")elif e.winerror == 232:  # 客户端断开print("客户端断开连接")self.connection_active = Falseif self.pipe_handle:win32file.CloseHandle(self.pipe_handle)self.pipe_handle = Noneawait asyncio.sleep(1)else:print(f"管道错误: {e}")await asyncio.sleep(1)except Exception as e:print(f"其他错误: {e}")await asyncio.sleep(1)async def _start_ffmpeg(self) -> None:"""启动FFmpeg进程"""with suppress(Exception):if self.ffmpeg_process:self.ffmpeg_process.terminate()await self.ffmpeg_process.wait()self.ffmpeg_process = await asyncio.create_subprocess_exec('ffmpeg','-f', 's16le','-ar', str(self.sample_rate),'-ac', str(self.channels),'-i', self.pipe_name,'-c:a', 'aac','-f', 'rtsp','-rtsp_transport', 'tcp','rtsp://localhost:8554/mystream',stdout=asyncio.subprocess.DEVNULL,stdin=asyncio.subprocess.DEVNULL,stderr=asyncio.subprocess.PIPE)asyncio.create_task(self._monitor_ffmpeg_errors())async def _monitor_ffmpeg_errors(self) -> None:"""监控FFmpeg错误输出"""while self.running and self.ffmpeg_process:line = await self.ffmpeg_process.stderr.readline()if not line:break# print(f"[FFmpeg Error] {line.decode().strip()}")async def _async_write_socket(self, data: bytes) -> None:"""安全写入管道"""try:if self.connection_active and self.pipe_handle:loop = asyncio.get_running_loop()await loop.run_in_executor(None, win32file.WriteFile, self.pipe_handle, data)except pywintypes.error as e:print(f"写入错误: {e}")self.connection_active = Falseawait self._reconnect_pipeline()except Exception as e:print(f"其他写入错误: {e}")self.connection_active = Falseasync def _reconnect_pipeline(self) -> None:"""完整重连流程"""print("启动重连流程...")self.connection_active = Falseif self.pipe_handle:win32file.CloseHandle(self.pipe_handle)self.pipe_handle = Noneawait asyncio.gather(self._async_create_pipe(),self._start_ffmpeg())async def _heartbeat(self) -> None:"""心跳维持机制"""while self.running:if self.connection_active:for i in range(10):if self.sending_audio < 0:await self._async_write_socket(self.silence)else:self.sending_audio -= 2await asyncio.sleep(0.2)else:await asyncio.sleep(0.5)def _sync_tts(self, text, tmp_filename):eng = pyttsx3.init()eng.save_to_file(text, 'temp3.wav')eng.runAndWait()#  eng.endLoop()async def _tts_worker(self, text: str) -> None:"""异步TTS处理核心"""await asyncio.get_event_loop().run_in_executor(None, self._sync_tts, text, 'temp3.wav')try:proc = await asyncio.create_subprocess_exec('ffmpeg','-hide_banner','-loglevel', 'error','-y','-i', 'temp3.wav','-f', 's16le','-acodec', 'pcm_s16le','-ar', str(self.sample_rate),'-ac', str(self.channels),'-',stdout=asyncio.subprocess.PIPE)sum_bytes = 0while chunk := await proc.stdout.read(4096):sum_bytes += len(chunk)await self._async_write_socket(chunk)self.sending_audio = int(sum_bytes * 10 / 48000)print(f"写入数据 x0.1s: {self.sending_audio}")finally:if os.path.exists('temp3.wav'):os.remove('temp3.wav')async def _input_handler(self) -> None:"""异步输入处理"""while self.running:try:text = await ainput("请输入文本(输入q退出): ")if text.lower() == 'q':self.running = Falsebreakif text.strip():await self._tts_worker(text)except Exception as e:print(f"输入错误: {str(e)}")async def run(self) -> None:"""主运行循环"""self.running = Truetasks = [asyncio.create_task(self._async_create_pipe()),asyncio.create_task(self._start_ffmpeg()),asyncio.create_task(self._input_handler()),asyncio.create_task(self._heartbeat()),]await asyncio.gather(*tasks)async def stop(self) -> None:"""安全关闭"""self.running = Falsewith suppress(Exception):if self.ffmpeg_process:self.ffmpeg_process.terminate()await self.ffmpeg_process.wait()if self.pipe_handle:win32pipe.DisconnectNamedPipe(self.pipe_handle)win32file.CloseHandle(self.pipe_handle)print("所有资源已释放")if __name__ == "__main__":controller = AsyncTTSController()try:asyncio.run(controller.run())except KeyboardInterrupt:asyncio.run(controller.stop())

独立的ffmpeg启动和监控的独立代码

验证了一下rtsp断线重建连结,也验证了 上面 的main.py的socket server退出后,ffmpeg自动重启连接。 要使用这个更稳健球的程序,需要

注释main.py run中的asyncio.create_task( self._start_ffmpeg()),

代码不用修改,把管道名这个快, 彻底修改为,ffmpeg认识的window样式,就可运行.

r’\.\pipe\tts_audio_pipe’

在这里插入图片描述
ffmg,py

import asyncio
from contextlib import suppress
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')class FFmpegManager:def __init__(self):self.ffmpeg_process = Noneself._retry_count = 0self._max_retries = 5self._retry_lock = asyncio.Lock()self._is_running = Falseself.sample_rate=24000self.channels=1self.socket_path = "/tmp/tts_audio.sock"async def _start_ffmpeg(self) -> None:"""带自动重试的FFmpeg启动函数"""async with self._retry_lock:await self._safe_terminate()try:socketid = 'unix:' + self.socket_pathself.ffmpeg_process =await asyncio.create_subprocess_exec('ffmpeg','-f', 's16le','-ar', str(self.sample_rate),'-ac', str(self.channels),'-i', socketid,  # 修改输入源为套接字路径'-c:a', 'aac','-f', 'rtsp','-rtsp_transport', 'tcp','rtsp://localhost:8554/mystream',stdout=asyncio.subprocess.DEVNULL,stdin=asyncio.subprocess.DEVNULL,stderr=asyncio.subprocess.PIPE)self._retry_count = 0  # 重置重试计数器asyncio.create_task(self._monitor_ffmpeg_errors())self._is_running = Trueexcept Exception as e:logging.error(f"FFmpeg启动失败: {str(e)}")await self._handle_retry()async def _monitor_ffmpeg_errors(self):"""增强型进程监控"""while self._is_running:logging.info("loop  error cathch")stderr = await self.ffmpeg_process.stderr.readline()if stderr:logging.error(f"FFmpeg错误输出: {stderr.decode().strip()}")# 检测进程状态return_code = self.ffmpeg_process.returncodeif return_code is not None:logging.warning(f"FFmpeg异常退出,返回码: {return_code}")self._is_running = Falseawait self._handle_retry()breakasync def _handle_retry(self):"""智能重试策略"""if self._retry_count >= self._max_retries:logging.critical("达到最大重试次数,放弃重启")return# 指数退避算法delay = min(2 ** self._retry_count, 30)  # 最大间隔30秒self._retry_count += 1logging.info(f"将在 {delay} 秒后尝试第 {self._retry_count} 次重启")await asyncio.sleep(delay)await self._start_ffmpeg()async def _safe_terminate(self):"""安全终止现有进程"""if self.ffmpeg_process:with suppress(Exception):self.ffmpeg_process.terminate()await self.ffmpeg_process.wait()self.ffmpeg_process = None
# 以下保持不变...
async def main():controller=FFmpegManager()try:await controller._start_ffmpeg()logging.info('rung')await asyncio.sleep(1160)except KeyboardInterrupt:logging.info(3)asyncio.run(controller._safe_terminate())
if __name__ == "__main__":asyncio.run(main())

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

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

相关文章

从0开始的操作系统手搓教程33:挂载我们的文件系统

目录 代码实现 添加到初始化上 上电看现象 挂载分区可能是一些朋友不理解的——实际上挂载就是将我们的文件系统封装好了的设备&#xff08;硬盘啊&#xff0c;SD卡啊&#xff0c;U盘啊等等&#xff09;&#xff0c;挂到我们的默认分区路径下。这样我们就能访问到了&#xff…

【图片批量转换合并PDF】多个文件夹的图片以文件夹为单位批量合并成一个PDF,基于wpf的实现方案

项目背景: 多个图片分布在不同文件夹,如何以文件夹为单位批量合并成一个PDF,还要保证文件夹里面图片大小和顺序 实现功能: 1、单张图片的转换PDF:一张图临时转一下 2、多张图片转换成PDF:多张图单独转成PDF 3、多级目录多张图转换成PDF:多级目录多张图单独转成多个PDF…

如何用Kimi生成PPT?秒出PPT更高效!

做PPT是不是总是让你头疼&#xff1f;&#x1f629; 快速制作出专业的PPT&#xff0c;今天我们要推荐两款超级好用的AI工具——Kimi 和 秒出PPT&#xff01;我们来看看哪一款更适合你吧&#xff01;&#x1f680; &#x1f947; Kimi&#xff1a;让PPT制作更轻松 Kimi的生成效…

从 MongoDB 到 TDengine,沃太能源实现 18 倍写入性能提升

导读 沃太能源是国内领先储能设备生产厂商&#xff0c;数十万储能终端遍布世界各地。此前使用 MongoDB 存储时序数据&#xff0c;但随着设备测点增加&#xff0c;MongoDB 在存储效率、写入性能、查询性能等方面暴露出短板。经过对比&#xff0c;沃太能源选择了专业时序数据库 …

数据库基本建表操作

1.登录数据库并创建数据库db_ck 创建完成后使用到我们创建的数据库。 2.创建表t_hero 根据hero属性包括&#xff08;id&#xff0c;name&#xff0c;nickname&#xff0c;age&#xff0c;gender&#xff0c;address&#xff0c;weapon&#xff0c;types&#xff09; 创建完…

OkHttp 之任务调度模块源码分析

一、引言 在现代网络应用开发中&#xff0c;高效的任务调度机制对于提升系统性能和用户体验至关重要。OkHttp 作为一款广泛使用的高性能 HTTP 客户端库&#xff0c;其任务调度模块在处理网络请求的并发、排队和执行等方面发挥着关键作用。本文将深入 OkHttp 源码&#xff0c;详…

复现无人机的项目,项目名称为Evidential Detection and Tracking Collaboration

项目名称为Evidential Detection and Tracking Collaboration&#xff0c;主要用于强大的反无人机系统&#xff0c;涉及新问题、基准和算法研究。下面介绍项目的复现步骤&#xff1a; 安装环境&#xff1a;使用Anaconda创建并激活名为edtc的虚拟环境&#xff0c;Python版本为3…

QwQ-32B 开源!本地部署+微调教程来了

今天&#xff0c;通义千问开源了推理模型QwQ-32B QwQ-32B 在一系列基准测试中进行了评估&#xff0c;测试了数学推理、编程能力和通用能力。以下结果展示了 QwQ-32B 与其他领先模型的性能对比&#xff0c;包括 DeepSeek-R1-Distilled-Qwen-32B、DeepSeek-R1-Distilled-Llama-7…

如何利用 Excel 表格实现精准文件批量重命名教程

在处理大量文件时&#xff0c;有时需要根据特定规则对文件名进行调整。如果您的文件名和新名称之间存在一对多的关系&#xff0c;并且这种关系可以通过 Excel 表格来管理&#xff0c;那么使用“简鹿文件批量重命名”软件中的“匹配对应名称命名”功能将是一个高效的选择。接下来…

开关模式电源转换器 EMI/EMC 的集成仿真

介绍 在电力电子领域&#xff0c;电磁干扰 &#xff08;EMI&#xff09; 和电磁兼容性 &#xff08;EMC&#xff09; 问题可以决定设计的成败。开关模式电源转换器虽然高效且紧凑&#xff0c;但却是电磁噪声的常见来源&#xff0c;可能会对附近的组件和系统造成严重破坏。随着…

Android 蓝牙工具类封装:支持经典蓝牙与 BLE,兼容高版本权限

为了优化经典蓝牙&#xff08;Classic Bluetooth&#xff09;和低功耗蓝牙&#xff08;Bluetooth Low Energy, BLE&#xff09;的操作&#xff0c;我们可以将功能封装到一个工具类中&#xff0c;支持扫描、连接、通信&#xff0c;并兼容高版本 Android 的动态权限申请。以下是完…

STM32 CAN模块原理与应用详解

目录 概述 一、CAN模块核心原理 1. CAN协议基础 2. STM32 CAN控制器结构 3. 波特率配置 二、CAN模块配置步骤&#xff08;基于HAL库&#xff09; 1. 初始化CAN外设 2. 配置过滤器 3. 启动CAN通信 三、数据收发实现 1. 发送数据帧 2. 接收数据帧&#xff08;中断方式…

PostgreSQL_安装部署

一、Windows系统下安装 1.下载安装包 登录PostgreSQL: Downloads官网&#xff1a; 选择14.12版本&#xff0c;点击下载&#xff1a; 2.安装PostgrSQL14.12 双击exe安装包程序&#xff0c;准备安装&#xff1a; 选择安装路径&#xff1a; 选择想安装的工具&#xff1a; 选择数…

init arry的作用,可以没有init arry嘛?(面试题)

https://bbs.kanxue.com/thread-282657.htm 对init_array段调用的方法进行Hook https://bbs.kanxue.com/thread-191092.htm init_array原理简单说明 https://bbs.kanxue.com/thread-280135.htm frida hook init_array自吐新解 init_array 的作用&#xff0c;以及是否可以没有 i…

蓝桥杯真题0团建dfs+哈希表/邻接表

dfs邻接表储存或者哈希表的运用&#xff0c;考察我们对数据的存储 本题核心就是在求从根节点开始的两棵树相同的最长序列&#xff0c;首先确定用dfs进行深搜&#xff0c;对于节点的形式可以用邻接表&#xff0c;邻接矩阵&#xff0c;哈希表来进行存储数据。下面看代码 邻接表 …

使用 AIStor、MLflow 和 KServe 将模型部署到 Kubernetes

在之前几篇关于 MLOps 工具的文章中&#xff0c;我展示了有多少流行的 MLOps 工具跟踪与模型训练实验相关的指标。我还展示了他们如何使用 MinIO 来存储作为模型训练管道一部分的非结构化数据。但是&#xff0c;一个好的 MLOps 工具应该做的不仅仅是管理您的实验、数据集和模型…

kali linux web扫描工具

Kali Linux是一款专为网络安全领域而打造的操作系统&#xff0c;提供了众多优秀的安全工具&#xff0c;其中就包括了强大的web扫描工具。Web扫描是网络安全检测的一个重要环节&#xff0c;它可以帮助安全专家检测网站的漏洞&#xff0c;提升网站的安全性。 Kali Linux中集成了…

Linux losetup循环设备

好的&#xff0c;以下是命令的中文解释和使用步骤&#xff1a; 命令解释&#xff1a; losetup -r /dev/loop0 /system/app.bin&#xff1a; losetup 是一个用于将文件与循环设备&#xff08;loop device&#xff09;关联的命令。-r 选项表示将循环设备设置为只读模式。/dev/lo…

【js逆向】

地址&#xff1a;aHR0cHM6Ly93d3cud2VpYm90b3AuY24vMi4wLw f12进入 debugger&#xff0c;过debugger 查看预览数据 全局搜索 请求网址中的 api.weibotop.cn 在下方疑似找到了加密和解密的函数 断点调试 控制台输出 那个n就是 常见的 cryptoJs库 const cryptoJs require(cry…

1.Intel BIOS 开发指南详细介绍

1. 引言 目的: Intel BIOS 开发指南旨在为开发者提供详细的指导,帮助他们理解和实现 Intel 平台上的 BIOS 功能。 适用对象: 适用于希望开发、调试和优化 BIOS 的硬件工程师、软件工程师和系统集成商。 版本信息: 确保你使用的是最新版本的指南,以获取最新的信息和最佳实…