
目录第一刀砍分辨率第二刀降帧率第三刀拉CRF三个参数怎么组合进阶GOP和帧类型先说结论:你不懂编码原理也能压视频。懂原理只是为了压得更聪明不是必须。你需要的就三个数分辨率、帧率、CRF。调这三个视频大小随便控。下面说为什么是这三个不管你看不看得懂记住结论拿去用就行。第一刀砍分辨率分辨率就是画面的宽×高。1080p是1920×1080720p是1280×720。像素数差了55%同样一段视频720p的文件大小大约是1080p的一半。肉眼看区别手机屏幕上基本分不出来人眼对分辨率感知有个临界点视频在动的时候你能分辨的细节远比静态图片少。一段运动的视频720p和1080p在6英寸手机屏幕上几乎看不出差别在电脑显示器上能看出一点但代价是文件大一倍。所以别跟你手机原厂的分辨率死磕。录的时候开4K是方便你后期裁剪但最后输出的时候降到1080p或者720p省出来的空间足够再存两段视频。代码实现用FFmpeg缩分辨率ffmpeg -i input.mp4 -vf scale1280:720 output.mp4scale1280:720就是缩到720p。如果你只想限制宽度让高度自适应写成scale1280:-1FFmpeg会自动计算高度保持比例。如果你想让高度限制宽度自适应写scale-1:720。代码实现用Python配合OpenCV缩分辨率import cv2 cap cv2.VideoCapture(input.mp4) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps int(cap.get(cv2.CAP_PROP_FPS)) # 缩到720p scale 720 / height new_w int(width * scale) new_h 720 fourcc cv2.VideoWriter_fourcc(*mp4v) out cv2.VideoWriter(output.mp4, fourcc, fps, (new_w, new_h)) while True: ret, frame cap.read() if not ret: break resized cv2.resize(frame, (new_w, new_h), interpolationcv2.INTER_LANCZOS4) out.write(resized) cap.release() out.release()INTER_LANCZOS4是OpenCV里质量最高的缩放算法比默认的线性插值好速度慢一点但值得。如果你处理的视频多或者机器性能差用INTER_AREA也行速度更快。实操建议 发微信720p。传B站1080p。自己收藏保留原片。第二刀降帧率帧率就是一秒钟有多少张图。30fps就是一秒30张60fps就是60张。电影标准是24fps所以24帧足够保证流畅从30降到24数据量减少20%视觉上基本没差别。从60降到30数据直接砍半动作还是一样的顺滑因为人眼对30帧以上的敏感度本来就低。但帧率不是越低越好。降到15fps画面就开始有卡顿感了看久了眼睛累。动画类内容降到15fps还能接受因为动画本身帧率就低。实拍视频最少24fps运动场景最少30fps这是底线。FFmpeg降帧率ffmpeg -i input.mp4 -r 24 output.mp4-r 24就是强制输出24fps。FFmpeg会从原视频里均匀抽帧丢掉多余的帧。如果你不想丢帧只想改播放速度慢放快放用-filter:v setpts...那是另一回事。Python配合OpenCV降帧率import cv2 cap cv2.VideoCapture(input.mp4) fps int(cap.get(cv2.CAP_PROP_FPS)) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) target_fps 24 # 计算抽帧间隔原帧率除以目标帧率 frame_interval round(fps / target_fps) fourcc cv2.VideoWriter_fourcc(*mp4v) out cv2.VideoWriter(output.mp4, fourcc, target_fps, (width, height)) frame_count 0 while True: ret, frame cap.read() if not ret: break # 每隔 frame_interval 帧取一帧 if frame_count % frame_interval 0: out.write(frame) frame_count 1 cap.release() out.release()抽帧的逻辑是取整帧间隔比如30fps降到24fps间隔是30/241.25取整就是每1-2帧取一帧。OpenCV没法处理小数帧率所以实际输出会是24fps近似值。如果你追求精确用FFmpeg更准。实操建议 实拍视频锁24fps游戏录屏或者快速运动保留30fps日常记录不需要60。第三刀拉CRF这个最狠也是最容易被忽略的。CRF是编码器的质量参数范围0到51。数值越小画质越好文件越大数值越大画质越差文件越小。CRF每增加6文件大小减半。CRF18是视觉无损文件巨大CRF23是高质量专业剪辑用的。CRF28是标准质量绝大多数在线视频就这个水平。CRF35往上是能看但能看出糊适合做缩略预览。CRF40以上就是马赛克除非你只传个草稿确认内容。为什么CRF每增加6文件就减半因为编码器里量化参数QP和CRF是对应关系QP每增加6DCT系数里被清零的高频分量大约多一倍。简单说就是丢弃的细节多一倍文件自然小一倍。FFmpeg设CRFffmpeg -i input.mp4 -crf 28 -c:v libx264 output.mp4-crf 28是质量参数-c:v libx264是编码器。H.264用CRFH.265HEVC也支持CRF取值范围一样是0-51。想用H.265就把libx264改成libx265文件还能再小20%-30%但播放兼容性差一些。直接调编码器参数通过FFmpeg-python库import ffmpeg input_file input.mp4 output_file output.mp4 ( ffmpeg .input(input_file) .output(output_file, vcodeclibx264, crf28) .run(overwrite_outputTrue) )ffmpeg-python是对FFmpeg命令的Python封装适合在脚本里集成。如果你不想每次调用命令行用这个库在代码里控制所有参数。overwrite_outputTrue是覆盖已有文件避免每次都要手动确认。实操建议 日常压缩无脑设28。画面静态内容多采访、讲课可以设30运动多球赛、舞蹈设26。别纠结先设28试试。三个参数怎么组合方案分辨率帧率CRF1分钟文件大小适用场景微信/钉钉发送720p (1280×720)243015-25 MB聊天发送、邮件附件、快速预览B站/抖音投稿1080p (1920×1080)302640-60 MB社交媒体发布、平台投稿自己收藏/备份原片分辨率原片帧率23不固定画质优先剪辑素材、家庭记录、归档存储FFmpeg命令ffmpeg -i input.mp4 -vf scale1280:720 -r 24 -crf 30 -c:v libx264 -preset medium output.mp4-preset medium是编码速度预设可选ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow。速度越快压出来的文件越大画质越差medium是平衡点。如果你不赶时间用slow能多压10%-15%的体积。关于码率很多人喜欢问码率要设多少。码率就是每秒的数据量单位是kbps或Mbps。你可以直接设码率比如-b:v 2M表示每秒最多2Mbit数据。但设码率的问题是你得知道什么内容设多少合适。静态画面2M够用运动画面2M就糊。所以更推荐用CRF而不是码率CRF是质量优先动态分配码率画面复杂的地方多用一点简单的地方少用一点。效果比固定码率好操作还简单。如果你一定要设码率参考值1080p视频普通内容2-4Mbps运动内容4-6Mbps静态内容1-2Mbps。固定码率模式(设码率为2Mbps)ffmpeg -i input.mp4 -b:v 2M -maxrate 2M -bufsize 4M output.mp4-b:v是平均码率-maxrate限制峰值码率-bufsize是缓冲区大小。固定码率模式下编码器保证文件大小精确可控但复杂画面会糊简单画面浪费带宽。一般只在直播或上传大小被严格限制时用。这些参数为什么能压这么多简单给你讲一下原理知道是怎么回事你用起来更安心。视频压缩干两件事第一是砍单帧里的细节这叫空间压缩。一张图里相邻像素颜色差不多编码器把图像转换到频率域高频细节纹理、噪点直接扔掉只保留低频大块颜色区域。这就是为什么压过的视频看起来柔和不锐利了因为细节没了。具体到代码层面DCT变换把8×8像素块转成频率系数量化矩阵把高频系数清零。你设的CRF值决定了量化矩阵的尺度因子CRF越高被清零的系数越多文件越小。第二是跨帧复用数据这叫时间压缩。这一帧的蓝天上飘着一朵云下一帧云挪了个位置编码器不重新存整片天空只记录云移动的方向和距离。背景完全不变的地方直接复制上一帧的数据不占新空间。运动估计算法在参考帧里搜索匹配块算出运动向量从哪移到哪然后把当前块减去参考块得到残差。残差通常很小压缩率高。CRF也影响残差的量化程度CRF越高残差被砍得越狠运动区域的细节损失越大。CRF控制的是第一件事分辨率影响第二件事的效率。分辨率越高像素越多需要复用的数据量就越大。帧率决定了每秒要处理多少帧帧率越高时间压缩的工作量越大。所以三个参数分别管三个维度分辨率管总量帧率管频次CRF管每一帧的丢弃比例。组合起来你想压多少就压多少。进阶GOP和帧类型如果你还想再压狠一点可以调GOPGroup of Pictures长度。GOP就是一组连续帧里包含多少个帧其中第一个是I帧完整图像后面是P帧单向预测和B帧双向预测。I帧最大P帧中等B帧最小。GOP越长I帧占比越小文件越小。默认GOP长度一般是250帧约10秒你可以拉到500帧甚至更高。但GOP太长有两个问题一是拖进度条的时候卡因为解码要从最近的I帧开始二是画面变化剧烈的地方P帧质量会下降。调GOP长度ffmpeg -i input.mp4 -g 300 -c:v libx264 -crf 28 output.mp4-g 300表示每300帧放一个I帧。如果做视频上传到平台平台会重新编码你的GOP结构所以调了也没用。如果是自己存着看或者发微信GOP拉长能小5%-10%。音频也得压很多人只压视频忘了音频。一段视频里音频占的空间可能比你想象的多。AAC编码128kbps的音频1分钟大约1MB看起来不多但如果你设成64kbps文件再小一半人耳基本分不出区别。代码实现音频压缩ffmpeg -i input.mp4 -c:v libx264 -crf 28 -c:a aac -b:a 64k output.mp4-c:a aac是音频编码器-b:a 64k是音频码率。AAC比MP3效率高同样码率下音质更好。64kbps适合语音和普通背景音乐128kbps适合音乐类内容。如果你不关心音频甚至可以用-an直接去掉音轨文件再小一截。实战脚本把上面所有参数打包成一个Python脚本import os import subprocess def compress_video(input_path, output_pathNone, scale720, fps24, crf28, audio_bitrate64): 压缩视频分辨率帧率CRF一次性搞定 if output_path is None: base, ext os.path.splitext(input_path) output_path f{base}_compressed{ext} cmd [ ffmpeg, -i, input_path, -vf, fscale-1:{scale}, # 高度固定宽度自适应 -r, str(fps), -c:v, libx264, -crf, str(crf), -preset, medium, -c:a, aac, -b:a, f{audio_bitrate}k, -movflags, faststart, # 便于网页播放 output_path ] print(f执行: { .join(cmd)}) subprocess.run(cmd, checkTrue) original os.path.getsize(input_path) / (1024 * 1024) compressed os.path.getsize(output_path) / (1024 * 1024) ratio (1 - compressed / original) * 100 print(f原始: {original:.1f}MB - 压缩后: {compressed:.1f}MB) print(f压缩率: {ratio:.1f}%) # 调用 compress_video(my_video.mp4, scale720, fps24, crf28)视频压缩不是什么高深技术。分辨率往下降帧率往下调CRF往上拉三个动作做完文件随便压到原来的20%以下。画质损失手机上看不出来。真要较真画质你就别压直接存原片。核心就一句用看不到的细节换看得到的空间这笔买卖不亏。希望这篇文章能帮到你如果觉得有用欢迎点赞、收藏、关注三连