Java调用FFmpeg实战:视频格式转换、合并、截图与播放全解析

1. 为什么要在Java里折腾FFmpeg

视频处理这件事,放在五年前我大概率会直接甩给前端或者专门的转码服务去做。但这两年明显感觉到,业务侧对"在Java服务里直接处理视频"的需求越来越硬——用户上传一个手机拍的MOV,后台得转成MP4才能保证全平台播放;运营给了一段背景音乐和一段无声视频,要求合成一条带BGM的推广片;内容审核环节需要从视频里抽帧截图做封面;甚至有些内部工具还要求能直接预览播放。这些需求如果每个都去对接第三方云服务,成本和延迟都扛不住,尤其是私有化部署的场景,根本不允许把视频往外传。

FFmpeg就是干这个的。它是一套开源的音视频处理工具集,命令行能力极强,几乎覆盖了格式转换、编解码、滤镜、合并、抽帧、推流等所有你能想到的操作。Java本身没有原生的视频处理能力,但Java可以通过ProcessBuilder或者Runtime.exec去调用FFmpeg的可执行文件,把命令行的能力"借"过来用。这条路子听起来有点土,但实测下来是最稳、最可控、依赖最少的方案。

这篇文章面向的是有一定Java基础、需要在服务端做视频处理的开发者。我会把格式转换、音视频合并、播放、截图这四个核心场景全部拆开讲,包括FFmpeg的安装配置、Java调用封装、参数选择逻辑、踩过的坑和排查方法。看完你应该能直接把这套东西搬进自己的项目里跑起来。

2. 环境准备与FFmpeg基础认知

2.1 FFmpeg的安装与验证

FFmpeg不是Java库,它是一个独立的可执行程序。所以第一步是在运行Java服务的机器上把它装好。Linux下最省事的方式是用包管理器,比如apt install ffmpeg或者yum install ffmpeg,但要注意发行版自带的版本可能偏老,某些新编码器不支持。我一般推荐去官网下载静态编译包,解压后把ffmpeg、ffprobe、ffplay三个二进制文件放到/usr/local/bin下,然后chmod +x赋予执行权限。

Windows下就是下载压缩包,解压到某个目录,比如D:\tools\ffmpeg,然后把D:\tools\ffmpeg\bin加到系统环境变量PATH里。装完之后在终端敲ffmpeg -version,能打印出版本号和编译配置就说明成功了。

注意:ffprobe是FFmpeg套件里专门用来探测媒体信息的工具,后面获取视频时长、分辨率、编码格式都要靠它,千万别只装ffmpeg一个文件。

2.2 Java调用FFmpeg的两种方式

Java调用外部程序主要有两条路。一条是Runtime.getRuntime().exec(),另一条是ProcessBuilder。我强烈建议用ProcessBuilder,原因有三个:第一,它可以把标准错误流和标准输出流合并,避免缓冲区满了导致进程卡死;第二,它支持设置工作目录和环境变量;第三,它的参数传递是列表形式,不用自己拼字符串,能规避路径里有空格导致的解析错误。

ProcessBuilder pb = new ProcessBuilder(); pb.command("ffmpeg", "-i", inputPath, outputPath); pb.redirectErrorStream(true); Process process = pb.start();

这里有个关键点:redirectErrorStream(true)必须开。FFmpeg的日志默认走stderr,如果你不合并也不读取,当输出内容超过操作系统管道缓冲区大小时,FFmpeg进程会阻塞在写日志上,Java这边waitFor()就永远等不到结束,表现为"程序卡死"。这个坑我踩过不止一次。

2.3 封装一个通用的命令执行工具

每个功能都写一遍ProcessBuilder太啰嗦,我一般会封装一个工具方法,负责执行命令、读取输出、等待结束、返回退出码。

public static int execute(List<String> command, long timeoutSeconds) throws Exception { ProcessBuilder pb = new ProcessBuilder(command); pb.redirectErrorStream(true); Process process = pb.start(); StringBuilder output = new StringBuilder(); try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { output.append(line).append("\n"); } } boolean finished = process.waitFor(timeoutSeconds, TimeUnit.SECONDS); if (!finished) { process.destroyForcibly(); throw new RuntimeException("FFmpeg执行超时"); } return process.exitValue(); }

退出码为0表示成功,非0就是失败,失败时把output打出来基本能定位到原因。超时机制一定要加,视频处理遇到损坏文件时FFmpeg可能长时间无响应,没有超时保护会把线程池拖垮。

3. 视频格式转换的核心实现

3.1 格式转换到底在转什么

很多人以为格式转换就是改个后缀名,其实远不止。一个视频文件包含容器格式和编码格式两个层面。容器是"盒子",比如MP4、MKV、AVI,决定了文件怎么组织音视频轨道、字幕、元数据;编码是"盒子里的东西怎么压缩的",比如H.264、H.265、VP9。所谓格式转换,可能是换容器不换编码,也可能是容器和编码一起换。

如果只是换容器,比如MKV转MP4,而内部编码本来就是H.264+AAC,那可以直接用流复制,速度极快,几乎不损失画质:

ffmpeg -i input.mkv -c copy output.mp4

-c copy的意思就是所有流原样复制,不做重新编码。这个操作几秒钟就能完成几个G的文件。

但如果源视频是H.265编码,目标设备只支持H.264,那就必须重新编码:

ffmpeg -i input.mp4 -c:v libx264 -c:a aac -preset medium -crf 23 output.mp4

这里的参数就有讲究了。-c:v libx264指定视频编码器,-c:a aac指定音频编码器。-preset控制编码速度和压缩率的平衡,可选ultrafast到veryslow,越慢压缩率越高但耗时越长。-crf是恒定质量因子,范围0到51,数值越小画质越好文件越大,23是默认值,18基本视觉无损,28就明显糊了。

3.2 Java中的格式转换封装

把上面的逻辑封装成Java方法,核心是判断是否需要重新编码。我的做法是先用ffprobe探测源文件的编码格式,如果和目标容器兼容就用-c copy,否则走重新编码。

public static void convert(String input, String output, String targetFormat) throws Exception { String videoCodec = probeCodec(input, "v"); String audioCodec = probeCodec(input, "a"); List<String> cmd = new ArrayList<>(); cmd.add("ffmpeg"); cmd.add("-i"); cmd.add(input); if (isCompatible(videoCodec, targetFormat) && isCompatible(audioCodec, targetFormat)) { cmd.add("-c"); cmd.add("copy"); } else { cmd.add("-c:v"); cmd.add("libx264"); cmd.add("-c:a"); cmd.add("aac"); cmd.add("-preset"); cmd.add("medium"); cmd.add("-crf"); cmd.add("23"); } cmd.add("-y"); cmd.add(output); int code = execute(cmd, 600); if (code != 0) { throw new RuntimeException("格式转换失败"); } }

-y参数表示输出文件已存在时直接覆盖,不加的话FFmpeg会交互式询问,在服务端环境下会直接卡住。

3.3 转换参数的取舍经验

关于-preset,我实测下来medium是性价比最高的档位。ultrafast虽然快,但生成的文件体积可能是medium的两倍还多,对于存储敏感的场景不划算。slow以上提升有限但耗时翻倍,除非是离线批处理任务,否则没必要。

-crf的选择要看业务。用户头像、短视频封面这类,23足够;如果是需要二次剪辑的素材,建议18;纯归档存储可以放到28。还有一个参数-movflags +faststart,对于MP4输出强烈建议加上,它会把元数据移到文件头部,让视频支持边下边播,否则必须整个文件下载完才能播放。

实操心得:转换大文件时,FFmpeg默认会输出大量进度日志。如果Java端不读取,进程会卡死。我的做法是在读取线程里只保留最后几行,或者用-loglevel error把日志级别调高,只输出错误信息。

4. 音视频合并的完整方案

4.1 合并场景的两种类型

音视频合并其实分两种情况。第一种是给无声视频配上一段音频,比如给监控录像加背景音乐;第二种是把多个视频片段拼接成一条长视频。这两种在FFmpeg里的处理方式完全不同,很多人会搞混。

给视频配音频,本质是替换或添加音频轨道:

ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a aac -shortest output.mp4

-shortest表示以较短的流为准结束输出,避免音频比视频长导致最后一段黑屏。-c:v copy保留原视频流不重新编码,只对音频编码,速度快。

多视频拼接则要用concat协议。先创建一个文本文件列出所有片段:

file 'part1.mp4' file 'part2.mp4' file 'part3.mp4'

然后执行:

ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

-safe 0允许使用绝对路径。这里有个硬性要求:所有片段的编码格式、分辨率、帧率必须完全一致,否则拼接出来的视频会出现音画不同步或者花屏。如果格式不统一,得先统一转码再拼接。

4.2 Java实现音视频合并

先看配音频的实现:

public static void mergeAudioVideo(String video, String audio, String output) throws Exception { List<String> cmd = Arrays.asList( "ffmpeg", "-i", video, "-i", audio, "-c:v", "copy", "-c:a", "aac", "-b:a", "192k", "-shortest", "-y", output ); int code = execute(cmd, 600); if (code != 0) { throw new RuntimeException("音视频合并失败"); } }

-b:a 192k指定音频码率,192kbps对于大多数场景够用了,追求音质可以上320k。

多视频拼接的Java实现稍微复杂一点,因为要先写临时列表文件:

public static void concatVideos(List<String> inputs, String output) throws Exception { Path listFile = Files.createTempFile("concat", ".txt"); StringBuilder sb = new StringBuilder(); for (String input : inputs) { sb.append("file '").append(input.replace("'", "'\\''")).append("'\n"); } Files.write(listFile, sb.toString().getBytes(StandardCharsets.UTF_8)); List<String> cmd = Arrays.asList( "ffmpeg", "-f", "concat", "-safe", "0", "-i", listFile.toString(), "-c", "copy", "-y", output ); int code = execute(cmd, 1200); Files.deleteIfExists(listFile); if (code != 0) { throw new RuntimeException("视频拼接失败"); } }

路径里的单引号要转义,否则列表文件解析会出错。临时文件用完记得删,不然跑久了磁盘会被塞满。

4.3 合并时的常见坑

第一个坑是音视频时长不一致。如果音频比视频长,不加-shortest的话输出视频会以音频长度为准,视频结束后是黑屏。如果视频比音频长,音频结束后是静音。业务上一般要求以视频为准,所以-shortest基本是必加的。

第二个坑是拼接时分辨率不一致。比如手机横屏拍的1920x1080和竖屏拍的1080x1920混在一起,直接concat会报错或者输出异常。解决办法是先用scale滤镜统一分辨率:

ffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4

这个命令会把视频等比缩放到1280x720的画布内,不足的部分用黑边填充,保证所有片段尺寸一致。

注意:force_original_aspect_ratio=decrease保证不拉伸变形,pad负责补黑边。如果直接scale=1280:720会强行拉伸,人物会变形。

5. 视频截图与封面抽取

5.1 截图的时机选择

视频截图最核心的参数是"截哪一帧"。最简单的做法是截第一帧:

ffmpeg -i input.mp4 -ss 00:00:01 -vframes 1 output.jpg

-ss指定时间点,-vframes 1表示只输出一帧。这里有个性能细节:-ss放在-i前面是快速定位,FFmpeg会直接跳到关键帧附近,速度快但可能不够精确;放在-i后面是精确解码,会从文件头解码到指定时间,慢但帧准确。对于封面抽取,快速定位就够了。

如果要做视频缩略图墙,可以按固定间隔抽帧:

ffmpeg -i input.mp4 -vf "fps=1/10" thumb_%03d.jpg

fps=1/10表示每10秒抽一帧,%03d是序号占位符,生成thumb_001.jpg、thumb_002.jpg这样。

5.2 Java实现截图功能

public static void captureFrame(String video, String output, String timePoint) throws Exception { List<String> cmd = Arrays.asList( "ffmpeg", "-ss", timePoint, "-i", video, "-vframes", "1", "-q:v", "2", "-y", output ); int code = execute(cmd, 120); if (code != 0) { throw new RuntimeException("视频截图失败"); } }

-q:v 2控制JPEG质量,范围1到31,数值越小质量越高,2基本是高质量。如果要生成PNG,把输出后缀改成.png即可,PNG是无损的但文件更大。

5.3 截图功能的进阶玩法

有时候业务需要"智能封面",也就是避开片头黑屏和片尾字幕,从中间截取。我的做法是先用ffprobe拿到视频总时长,然后取30%位置作为截图点:

public static double getDuration(String video) throws Exception { List<String> cmd = Arrays.asList( "ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", video ); ProcessBuilder pb = new ProcessBuilder(cmd); pb.redirectErrorStream(true); Process process = pb.start(); try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream()))) { String line = reader.readLine(); return Double.parseDouble(line.trim()); } }

拿到时长后乘以0.3就是截图时间点。这个比例是我试出来的经验值,太靠前容易截到黑屏,太靠后容易截到片尾。

实操心得:截图输出路径的目录必须提前创建好,FFmpeg不会自动建目录。如果目录不存在,它会直接报错退出。我一般会在调用前用Files.createDirectories确保目录存在。

6. 视频播放能力的实现思路

6.1 服务端"播放"的本质

严格来说,Java服务端并不负责"播放"视频,播放是客户端的事。但服务端需要做的是让视频能够被播放,这涉及两个层面:一是转码成浏览器或播放器支持的格式,二是支持HTTP Range请求实现拖动进度条。

浏览器原生支持最好的是MP4(H.264+AAC)和WebM。如果用户上传的是AVI、RMVB这些老格式,必须先转成MP4。转码时加上-movflags +faststart,让元数据前置,这样浏览器不用等整个文件下载完就能开始播放。

6.2 支持拖动进度的关键

视频能播放但拖不动进度条,这是很多人遇到的问题。根源在于服务端没有正确处理HTTP的Range请求。播放器拖动时会发送Range: bytes=1000-2000这样的请求头,服务端必须返回206状态码和对应的字节片段。

如果用Spring Boot,可以用ResourceHttpRequestHandler或者自己写Controller处理:

@GetMapping("/video/{id}") public ResponseEntity<Resource> play(@PathVariable String id, @RequestHeader(value = "Range", required = false) String range) throws Exception { File file = getVideoFile(id); long length = file.length(); if (range == null) { return ResponseEntity.ok() .contentType(MediaType.parseMediaType("video/mp4")) .contentLength(length) .body(new FileSystemResource(file)); } String[] ranges = range.replace("bytes=", "").split("-"); long start = Long.parseLong(ranges[0]); long end = ranges.length > 1 ? Long.parseLong(ranges[1]) : length - 1; long contentLength = end - start + 1; InputStream is = new RandomAccessFile(file, "r").getChannel() .map(FileChannel.MapMode.READ_ONLY, start, contentLength) .newInputStream(); return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT) .contentType(MediaType.parseMediaType("video/mp4")) .header("Accept-Ranges", "bytes") .header("Content-Range", "bytes " + start + "-" + end + "/" + length) .contentLength(contentLength) .body(new InputStreamResource(is)); }

Accept-Ranges: bytes这个响应头必须返回,否则播放器不知道服务端支持分段请求,进度条就是灰的。

6.3 播放相关的转码策略

如果视频需要加密或者加水印,就不能直接返回原文件,得实时转码。实时转码的性能开销很大,一个1080P的视频转码能吃掉好几个CPU核心。我的建议是异步预转码,用户上传后立即触发转码任务,转好了再提供播放地址,而不是在播放请求里同步转码。

如果确实需要实时处理,可以用FFmpeg的管道输出,把转码结果直接写到HTTP响应流里:

ffmpeg -i input.mp4 -f mp4 -movflags frag_keyframe+empty_moov -pipe:1

frag_keyframe+empty_moov生成的是碎片化MP4,适合流式传输。Java端读取进程的输出流,边读边写到HttpServletResponse的OutputStream。

注意:实时转码场景下,客户端断开连接后必须主动销毁FFmpeg进程,否则会留下僵尸进程持续消耗CPU。可以在finally块里调用process.destroyForcibly()。

7. 常见问题与排查技巧实录

7.1 问题速查表

问题现象可能原因排查方法解决方案
进程卡死不返回未读取输出流导致缓冲区满检查是否调用redirectErrorStream并读取合并流并持续读取
转换后无声音音频编码不兼容用ffprobe查看音频编码指定-c:a aac重新编码
拼接后音画不同步片段帧率不一致检查各片段帧率统一转码后再拼接
截图是黑屏截到了片头黑帧换时间点重试取视频30%位置截图
播放拖不动进度未支持Range请求抓包看是否返回206实现分段响应
中文路径报错编码问题查看FFmpeg错误输出统一用UTF-8并避免中文路径
输出文件0字节磁盘满或权限不足检查磁盘和目录权限清理空间或改权限

7.2 几个容易被忽略的细节

第一个是路径问题。FFmpeg对中文路径和空格路径的处理在不同操作系统上表现不一致。我的做法是统一把输入输出文件放到临时目录,用UUID命名,处理完再移动到目标位置。这样既避免了编码问题,也防止了文件名冲突。

第二个是并发控制。FFmpeg是CPU密集型任务,一个转码任务可能占满多个核心。如果Java服务同时处理多个转码请求,机器会直接卡死。我一般会用信号量限制并发数,比如Semaphore(2),同时最多跑两个转码任务,超出的排队等待。

private static final Semaphore TRANSCODE_SEMAPHORE = new Semaphore(2); public static void transcodeWithLimit(String input, String output) throws Exception { TRANSCODE_SEMAPHORE.acquire(); try { convert(input, output, "mp4"); } finally { TRANSCODE_SEMAPHORE.release(); } }

第三个是临时文件清理。转码过程中会产生大量临时文件,如果异常退出没有清理,磁盘很快会被占满。建议用try-finally确保临时文件被删除,或者定期跑清理任务。

7.3 性能优化的几个方向

如果转码量很大,可以考虑用硬件加速。NVIDIA显卡可以用h264_nvenc编码器,Intel核显可以用h264_qsv,速度比纯CPU快好几倍。但硬件加速的画质通常略逊于libx264,需要根据业务权衡。

ffmpeg -i input.mp4 -c:v h264_nvenc -preset p4 -cq 23 output.mp4

-cq是NVENC的质量参数,类似CRF。-preset p4是NVENC的预设,p1最快p7最慢。

另一个方向是分片并行。长视频可以切成多个片段并行转码,最后拼接。但这样会引入片段边界的问题,实现复杂度高,除非是超长视频否则不建议。

实操心得:转码任务的日志一定要落盘。FFmpeg的报错信息很详细,但如果不保存,出问题时只能看到"退出码1",根本没法排查。我一般会把每个任务的完整输出写到日志文件,按任务ID命名,保留7天。

8. 一套可复用的封装设计

把上面所有功能整合起来,我一般会设计一个FfmpegService类,对外暴露几个高层方法:convert、merge、capture、probe。内部统一走命令执行工具,统一处理超时、日志、并发限制。配置项比如FFmpeg路径、超时时间、并发数放到配置文件里,不同环境可以调整。

FFmpeg路径建议做成可配置的,因为开发机可能是Windows,服务器是Linux,硬编码路径换环境就挂。用@Value("${ffmpeg.path:ffmpeg}")这种形式,默认值ffmpeg表示从PATH里找,特殊环境再覆盖。

还有一点,FFmpeg的版本差异会导致某些参数不兼容。比如老版本不支持某些新编码器,新版本废弃了某些旧参数。建议在服务启动时执行一次ffmpeg -version,把版本号打到日志里,出问题时能快速定位是不是版本问题。

这套东西我在几个项目里都用过,从日处理几十个视频的小工具到日处理上万条的批处理服务都跑得动。核心就是三点:命令执行要防卡死、并发要限流、临时文件要清理。把这三点做好,剩下的就是按业务需求调参数了。

相关新闻

代码注释与格式化:从可读性到团队协作的工程实践

代码注释与格式化:从可读性到团队协作的工程实践

前阵子我接手一个历史遗留模块&#xff0c;代码里躺着一行注释&#xff1a;“这段逻辑不要动&#xff0c;动了会出线上事故。”没有署名&#xff0c;没有日期&#xff0c;也没有任何原因说明。我盯着它看了很久&#xff0c;最后还是把那段重构掉了——结果注释里担心的问题&…

2026/10/20 5:49:17 阅读更多 →
artcraft从创意到实物:艺术手工融合的完整实操指南

artcraft从创意到实物:艺术手工融合的完整实操指南

1. 从"artcraft"这个名字说起&#xff1a;它到底想解决什么问题第一次看到"artcraft"这个词&#xff0c;我脑子里蹦出来的第一反应是"艺术"加"手艺"的组合。这不是一个随便拼出来的名字&#xff0c;它背后指向的是一类非常具体的东西—…

2026/10/20 5:49:17 阅读更多 →
UE4 ListView性能优化实战:EntryWidget回收机制与选型指南

UE4 ListView性能优化实战:EntryWidget回收机制与选型指南

1. 为什么ListView值得单独拎出来聊做UE4 UI开发的人&#xff0c;迟早会撞上ListView这堵墙。不是因为它难用&#xff0c;恰恰相反&#xff0c;是因为它太好用&#xff0c;好用到很多人第一次接触就把它当成万能列表控件&#xff0c;结果项目做到中期&#xff0c;列表一卡、数据…

2026/10/20 5:49:17 阅读更多 →

最新新闻

AI大模型自动化测试实战:全流程智能测试设计与落地

AI大模型自动化测试实战:全流程智能测试设计与落地

我在一线做测试自动化和质量保障已经快十年&#xff0c;说实话&#xff0c;前八年大部分时间都花在写脚本、调框架、跟环境和用例维护作斗争上。最近这两年&#xff0c;AI大模型自动化这个方向确实改变了我的工作节奏。之前接手某个跨平台系统&#xff0c;每个版本回归要花上两…

2026/10/20 6:24:32 阅读更多 →
基于博途S7-1200的四病房八床位呼叫控制系统设计与梯形图实现

基于博途S7-1200的四病房八床位呼叫控制系统设计与梯形图实现

做PLC项目这些年&#xff0c;呼叫提示类的控制系统看着不难&#xff0c;但真落到实处&#xff0c;要照顾的细节远比想象中多。最近完成的一套“No.101 博途1200 PLC四病房八床位呼叫控制系统”&#xff0c;就是典型的中小型离散控制任务&#xff1a;四间病房、八个床位&#xf…

2026/10/20 6:24:32 阅读更多 →
Artcraft:数字创作中的手工感与参数直觉

Artcraft:数字创作中的手工感与参数直觉

1. “Artcraft”不是新软件&#xff0c;而是一类被长期低估的创作范式最近在几个设计类社区和开源项目讨论区里&#xff0c;“artcraft”这个词突然高频出现&#xff0c;但翻遍主流技术文档、设计手册甚至英文维基&#xff0c;都找不到一个权威定义。它既不指代某款刚发布的AI绘…

2026/10/20 6:24:32 阅读更多 →
演示文稿自动化工具设计:模板驱动与数据填充实战

演示文稿自动化工具设计:模板驱动与数据填充实战

1. 从零拆解一个演示文稿自动化工具的设计思路第一次看到 "ppt-master" 这个命名&#xff0c;我的直觉是&#xff1a;这大概率是一个围绕演示文稿&#xff08;PPT&#xff09;做自动化生成或批量处理的工具项目。在办公自动化这个领域摸爬滚打这些年&#xff0c;我见…

2026/10/20 6:24:32 阅读更多 →
WSL2 + pnpm 环境下部署 Paperclip:从 Node 版本到权限控制

WSL2 + pnpm 环境下部署 Paperclip:从 Node 版本到权限控制

WSL2 pnpm 环境下部署 Paperclip&#xff1a;从 Node 版本到权限控制 【免费下载链接】paperclip The open-source app everyone uses to manage agents at work 项目地址: https://gitcode.com/GitHub_Trending/papercl/paperclip Paperclip 把自己定位为"每个人…

2026/10/20 6:24:32 阅读更多 →
AEI@DC解决方案

AEI@DC解决方案

面向未来&#xff0c;数据中心运维需要从“人力密集型”向“技术密集型”演进&#xff0c;借助Agentic AI技术打造全新的智能运维体系。实现全栈数据采集、全局统一可视&#xff0c;更早地发现风险、更快地解决问题、更极致的算效和能效、更精准的运营决策&#xff0c;最终实现…

2026/10/20 6:23:32 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →