视频元数据
查看视频文件分辨率 / 时长 / 编码 / 帧率 / 比特率 · 浏览器本地解析
编码/时长/码率/分辨率
查看视频文件分辨率 / 时长 / 编码 / 帧率 / 比特率 · 浏览器本地解析
浏览器原生支持:MP4 (H.264/H.265) / WebM (VP8/VP9/AV1) / Ogg (Theora)。Safari 还支持 MOV。
提取信息:分辨率(width × height)/ 时长 / 视频/音频轨道数 / 容器类型。详细编码参数(如 H.264 profile / 比特率)需要 FFmpeg.wasm 解析。
本地处理:所有元数据用浏览器 HTMLVideoElement API 读取,文件永不上传。
了解工具定位 · 使用场景 · 对比优势
上传一个视频文件,立即提取编码格式、时长、码率、分辨率等元数据。适合视频编辑核对素材参数、开发者调试输出、内容创作者检查上传规格。文件仅在浏览器本地处理,不上传服务器。
视频创作者在 B 站 / 抖音等平台投稿,平台对编码、码率、分辨率有明确要求(如 H.264、≤ 20 Mbps、1080p)。本工具一键读取本地视频的编码格式、总码率、分辨率、时长,提前发现不符合平台规格的视频,避免上传后转码失败或画质被压缩。
后期制作团队需将 200 个素材统一转码为 ProRes 422,但原始素材编码混杂(H.264 / H.265 / VP9),码率从 5 Mbps 到 50 Mbps 不等。本工具批量读取每个文件的编码、码率、分辨率,快速筛选出码率过低(< 10 Mbps)或分辨率异常的素材,避免转码后出现画质断层或黑边。
从网盘 / 下载站获取的 MP4 文件可能因传输中断导致时长显示异常(如实际 10 分钟但元数据只记录 3 秒)。本工具读取视频的精确时长和编码信息,与文件大小对比——若时长极短但体积巨大,或编码字段为空,可判定文件损坏,避免导入剪辑软件后崩溃。
直播运营者使用 OBS 录制 4K 直播流,但回看发现画面模糊。本工具读取录制文件的码率与分辨率——若分辨率标注 4K 但码率仅 8 Mbps,说明 OBS 设置中码率过低导致画质损失;若编码为 H.265 但播放器不支持,则需重新封装。帮助快速定位录制参数问题。
手机拍摄的 4K 60fps 视频体积巨大(1 分钟约 400 MB),想压缩到 50 MB 以内发送微信,但不知该降到多少码率。本工具读取原始视频的码率和分辨率,给出压缩建议:若原始码率 50 Mbps,压缩到 10 Mbps 后分辨率保持 1080p,体积可缩小 80%,同时画质肉眼几乎无差异。
| 维度 | 本工具 | MediaInfo | 传统方法(ffprobe CLI) |
|---|---|---|---|
| 数据隐私 | 纯浏览器处理,不上传文件 | 需下载安装,本地处理 | 本地命令行处理,无上传 |
| 使用门槛 | 打开网页即用,无需安装 | 需下载安装,有学习成本 | 需熟悉命令行操作 |
| 处理速度 | 1 秒内出结果 | 1-2 秒 | 2-5 秒(含命令输入) |
| 文件大小限制 | 取决于浏览器内存,通常 ≤2GB | 无限制 | 无限制 |
| 平台兼容 | 所有现代浏览器(Win/Mac/Linux) | Windows/macOS/Linux 桌面端 | 需安装 FFmpeg 的环境 |
| 批量处理 | 单次单文件 | 支持批量拖拽 | 支持脚本批量处理 |
| 输出格式 | 结构化表格,直接可读 | 多视图(文本/树/图表) | 原始文本输出,需自行解析 |
| 离线可用 | 需网络加载 WASM | 完全离线 | 完全离线 |
上手步骤 · 输入输出 · 避坑提示
| 输入 | 输出 | 说明 |
|---|---|---|
| https://example.com/videos/sample.mp4 | 编码: H.264 | 时长: 00:05:30.12 | 码率: 2.5 Mbps | 分辨率: 1920x1080 | 典型场景:最常见的网络视频格式与分辨率 |
| https://example.com/videos/short_clip.mov | 编码: ProRes 422 | 时长: 00:00:03.50 | 码率: 45.8 Mbps | 分辨率: 3840x2160 | 边界 case:4K 高码率短视频,常见于专业剪辑 |
| https://example.com/videos/animation.webm | 编码: VP9 | 时长: 00:02:15.00 | 码率: 1.2 Mbps | 分辨率: 1280x720 | 典型场景:WebM 格式与 VP9 编码,用于网页 |
| https://example.com/videos/old_video.avi | 编码: MPEG-4 Visual | 时长: 01:23:45.30 | 码率: 1.8 Mbps | 分辨率: 720x576 | 边界 case:老旧 AVI 容器与标清分辨率 |
| https://example.com/videos/vertical_9_16.mp4 | 编码: H.265 | 时长: 00:00:15.00 | 码率: 3.0 Mbps | 分辨率: 1080x1920 | 典型场景:竖屏短视频,常见于社交媒体 |
| https://example.com/videos/very_low_bitrate.3gp | 编码: H.263 | 时长: 00:10:00.00 | 码率: 64 Kbps | 分辨率: 176x144 | 边界 case:极低码率与分辨率,常见于老式手机 |
| https://example.com/videos/corrupted_header.mp4 | 错误:无法解析文件头,请确认文件未损坏 | 易错 case:文件头损坏时工具无法读取元数据 |
| https://example.com/videos/audio_only.m4a | 错误:输入文件不含视频轨道 | 易错 case:纯音频文件会被工具识别并提示 |
C:\Users\张三\Downloads\demo.mp4直接拖拽视频文件到上传区域,或点击上传按钮选择文件工具运行在浏览器中,无法访问本地文件系统路径;必须通过 File API 读取文件内容
上传一个 .txt 文本文件或 .zip 压缩包只上传 .mp4 .mov .avi .mkv .webm 等视频格式文件FFmpeg 在解析非视频文件时会立即报错或返回空结果;工具前端对 MIME 类型做了过滤,但用户仍可能绕过
看到输出 "码率: 2000" 以为单位是 kbps输出码率单位是 kbps(千比特每秒),2000 kbps ≈ 2 MbpsFFmpeg 默认以 bit/s 计算,工具内部转换为 kbps 显示;部分播放器显示 Mbps 导致用户误解
只看分辨率(如 1920×1080)判断视频清晰同时检查码率:1080p 视频码率低于 1000 kbps 时画质明显差于 720p 高码率分辨率只决定像素数量,码率决定每个像素分配的数据量;低码率高分辨率反而更模糊
认为 60fps 一定比 30fps 流畅检查帧率的同时查看编码格式(H.264 vs H.265)和码率是否匹配60fps 需要双倍码率才能保持同等画质;低码率 60fps 可能比高码率 30fps 更卡顿
从下载一半的网站复制 .mp4 文件直接上传先用播放器确认视频能完整播放,或检查文件大小是否与源文件一致FFmpeg 对损坏文件会返回部分元数据(如时长可能为 0),但工具无法自动修复;结果不可靠
看到 "时长: 01:23:45.678" 以为是 1 小时 23 分 45 秒 678 毫秒正确理解:01:23:45.678 = 1 小时 23 分 45 秒 678 毫秒,与常见播放器显示一致FFmpeg 输出时长格式为 HH:MM:SS.mmm,部分用户误以为最后两位是帧数或百分秒
上传一个 4K 电影文件(约 15GB)先确认文件大小:浏览器 WASM 内存限制通常 2-4GB,建议上传 ≤1GB 的片段WASM 版 FFmpeg 在浏览器中运行,受限于浏览器内存(Chrome 约 2GB);超大文件会导致标签页崩溃
公式推导 · 流程图解 · 依据出处
bitrate = file_size / duration
bitrate — 视频码率,单位 bpsfile_size — 视频文件总大小,单位 bitduration — 视频总时长,单位秒一个 1080p 视频,文件大小 500 MB(500 × 8 × 1024 × 1024 = 4,194,304,000 bit),时长 120 秒。码率 = 4,194,304,000 / 120 ≈ 34,952,533 bps ≈ 34.95 Mbps。
适用于恒定码率(CBR)或平均码率(ABR)视频。可变码率(VBR)视频的瞬时码率会大幅波动,此公式仅计算整体平均码率。数据来源:ITU-T H.264 / H.265 标准及 FFmpeg 文档。
3 种主流语言 · 复制即用
import subprocess
import json
def get_video_metadata(filepath: str) -> dict:
"""使用 ffprobe 获取视频编码、时长、码率、分辨率"""
cmd = [
"ffprobe", "-v", "quiet", "-print_format", "json",
"-show_format", "-show_streams", filepath
]
result = subprocess.run(cmd, capture_output=True, text=True)
data = json.loads(result.stdout)
# 取第一个视频流
video_stream = next(s for s in data["streams"] if s["codec_type"] == "video")
metadata = {
"codec": video_stream.get("codec_name"),
"duration": float(data["format"]["duration"]), # 秒
"bitrate": int(data["format"]["bit_rate"]), # bps
"width": video_stream.get("width"),
"height": video_stream.get("height"),
}
return metadata
# 示例:假设本地有 input.mp4
# print(get_video_metadata("input.mp4"))
# 输出示例:{'codec': 'h264', 'duration': 120.5, 'bitrate': 2500000, 'width': 1920, 'height': 1080}package main
import (
"encoding/json"
"fmt"
"os/exec"
"strconv"
)
type VideoMeta struct {
Codec string `json:"codec"`
Duration float64 `json:"duration"`
Bitrate int `json:"bitrate"`
Width int `json:"width"`
Height int `json:"height"`
}
func getVideoMetadata(filepath string) (*VideoMeta, error) {
// 使用 ffprobe 输出 JSON
cmd := exec.Command("ffprobe", "-v", "quiet", "-print_format", "json",
"-show_format", "-show_streams", filepath)
out, err := cmd.Output()
if err != nil {
return nil, err
}
var raw map[string]interface{}
if err := json.Unmarshal(out, &raw); err != nil {
return nil, err
}
streams := raw["streams"].([]interface{})
var videoStream map[string]interface{}
for _, s := range streams {
st := s.(map[string]interface{})
if st["codec_type"] == "video" {
videoStream = st
break
}
}
format := raw["format"].(map[string]interface{})
duration, _ := strconv.ParseFloat(format["duration"].(string), 64)
bitrate, _ := strconv.Atoi(format["bit_rate"].(string))
meta := &VideoMeta{
Codec: videoStream["codec_name"].(string),
Duration: duration,
Bitrate: bitrate,
Width: int(videoStream["width"].(float64)),
Height: int(videoStream["height"].(float64)),
}
return meta, nil
}
func main() {
// 示例:假设本地有 input.mp4
// meta, err := getVideoMetadata("input.mp4")
// if err != nil { panic(err) }
// fmt.Printf("%+v\n", meta)
// 输出:&{Codec:h264 Duration:120.5 Bitrate:2500000 Width:1920 Height:1080}
}const { execSync } = require('child_process');
function getVideoMetadata(filepath) {
// 调用 ffprobe 获取 JSON 格式的元数据
const cmd = `ffprobe -v quiet -print_format json -show_format -show_streams "${filepath}"`;
const stdout = execSync(cmd).toString();
const data = JSON.parse(stdout);
// 找到第一个视频流
const videoStream = data.streams.find(s => s.codec_type === 'video');
return {
codec: videoStream.codec_name,
duration: parseFloat(data.format.duration), // 秒
bitrate: parseInt(data.format.bit_rate, 10), // bps
width: videoStream.width,
height: videoStream.height,
};
}
// 示例:假设本地有 input.mp4
// const meta = getVideoMetadata('input.mp4');
// console.log(meta);
// 输出:{ codec: 'h264', duration: 120.5, bitrate: 2500000, width: 1920, height: 1080 }8 个高频疑问