|
|
本帖最后由 dsyszy 于 2026-11-14 20:10 编辑
使用 chrome 播放 mp4 很容易发现问题。
如果不快进,后续的播放会一直都是音画不同步,所以必须快进才能让音画重新同步。
使用专门的视频播放器软件播放可能无法及时发现问题,因为播放器做了处理,遇到丢帧自动快进。
由于大家看视频都是快进,所以更难发现视频源出问题的地方。
我也是最近看某堂 自译字幕区,很多视频出现 原档待补,还提到坏档链接,但是没有提到具体出问题的地方。
自己也下载了几部视频也没发现问题,直到今天下载了 4k2 论坛的 mikr-133 视频 ,播放过程发现了问题。
第一次发现画面卡顿的地方 01:25:30 开始,画面卡顿几秒,之后就是音画不停步。(我也是快进随机看的,反复几次才发现问题)
由于人工找容易漏掉,加上近期确实出现非常多的视频有音画不同步的问题。
于是写一个php脚本用于检测视频是否有问题,脚本不太完善,大家可以利用ai优化或者转换成其他的编程语言进行测试。
mikr-133 有问题的地方(后续发现有问题的视频会在 4k2 对应的视频下面评论,大家注意一下就可以):
- [视频间隔异常] 00:37:30.683(2250.683s)-> 00:37:32.751(2252.751s),间隔 2.069s
- [视频间隔异常] 00:49:30.902(2970.902s)-> 00:49:32.971(2972.971s),间隔 2.069s
- [视频间隔异常] 01:01:30.621(3690.621s)-> 01:01:32.690(3692.690s),间隔 2.069s
- [视频间隔异常] 01:13:30.841(4410.841s)-> 01:13:32.909(4412.909s),间隔 2.069s
- [视频间隔异常] 01:25:30.560(5130.560s)-> 01:25:32.628(5132.628s),间隔 2.069s
复制代码
测试脚本:
- <?php
- // ===== 配置 =====
- $file = __DIR__ . '/test.mp4';
- $videoGapThreshold = 0.1; // 视频帧间隔超过 100ms 报警
- $audioGapTolerance = 0.002; // 音频间断容差 2ms
- function formatTime($seconds) {
- $hours = (int) floor($seconds / 3600);
- $minutes = (int) floor(fmod($seconds, 3600) / 60);
- $seconds = fmod($seconds, 60);
- return sprintf('%02d:%02d:%06.3f', $hours, $minutes, $seconds);
- }
- // ===== 视频 Packet 检测 =====
- echo "开始检测视频 Packet...\n";
- $videoPackets = [];
- $cmd = 'ffprobe -v error'
- . ' -select_streams v:0'
- . ' -show_packets'
- . ' -show_entries packet=pts_time,duration_time'
- . ' -of csv=p=0 '
- . escapeshellarg($file);
- $handle = popen($cmd . ' 2>&1', 'r');
- if ($handle) {
- while (($line = fgets($handle)) !== false) {
- $data = str_getcsv(trim($line), ',', '"', '');
- if (!isset($data[0]) || !is_numeric($data[0])) {
- continue;
- }
- $pts = (float)$data[0];
- $duration = isset($data[1]) && is_numeric($data[1])
- ? (float)$data[1]
- : 0;
- $videoPackets[] = [
- 'pts' => $pts,
- 'duration' => $duration
- ];
- if (count($videoPackets) % 5000 === 0) {
- echo "视频已读取 " . count($videoPackets) . " 个 Packet\n";
- flush();
- }
- }
- $result = pclose($handle);
- echo "视频 Packet 读取完成,数量:" . count($videoPackets) . "\n";
- }
- // 按显示时间 PTS 排序,避免 B 帧导致顺序错乱
- usort($videoPackets, function ($a, $b) {
- return $a['pts'] <=> $b['pts'];
- });
- // 检测视频时间间隔
- $lastPts = null;
- $videoErrors = 0;
- foreach ($videoPackets as $packet) {
- $pts = $packet['pts'];
- if ($lastPts !== null) {
- $gap = $pts - $lastPts;
- if ($gap > $videoGapThreshold) {
- printf(
- "[视频间隔异常] %s(%.3fs)-> %s(%.3fs),间隔 %.3fs\n",
- formatTime($lastPts),
- $lastPts,
- formatTime($pts),
- $pts,
- $gap
- );
- $videoErrors++;
- } elseif ($gap <= 0) {
- printf(
- "[视频时间戳重复] %s(%.3fs)\n",
- formatTime($pts),
- $pts
- );
- $videoErrors++;
- }
- }
- $lastPts = $pts;
- }
- echo "视频检测完成,异常数量:{$videoErrors}\n";
- // 释放视频 Packet 数据
- unset($videoPackets);
- // ===== 音频 Packet 检测 =====
- echo "\n开始检测音频 Packet...\n";
- $audioCount = 0;
- $audioErrors = 0;
- $lastPts = null;
- $lastDuration = 0;
- $cmd = 'ffprobe -v error'
- . ' -select_streams a:0'
- . ' -show_packets'
- . ' -show_entries packet=pts_time,duration_time'
- . ' -of csv=p=0 '
- . escapeshellarg($file);
- $handle = popen($cmd . ' 2>&1', 'r');
- if ($handle) {
- while (($line = fgets($handle)) !== false) {
- $data = str_getcsv(trim($line), ',', '"', '');
- if (!isset($data[0]) || !is_numeric($data[0])) {
- continue;
- }
- $pts = (float)$data[0];
- $duration = isset($data[1]) && is_numeric($data[1])
- ? (float)$data[1]
- : 0;
- $audioCount++;
- if ($lastPts !== null && $lastDuration > 0) {
- $gap = $pts - ($lastPts + $lastDuration);
- if ($gap > $audioGapTolerance) {
- printf(
- "[音频间断] %s(%.3fs),间断 %.3fs\n",
- formatTime($pts),
- $pts,
- $gap
- );
- $audioErrors++;
- } elseif ($gap < -$audioGapTolerance) {
- printf(
- "[音频 Packet 重叠] %s(%.3fs),重叠 %.3fs\n",
- formatTime($pts),
- $pts,
- abs($gap)
- );
- $audioErrors++;
- }
- }
- $lastPts = $pts;
- $lastDuration = $duration;
- if ($audioCount % 5000 === 0) {
- echo "音频已检测 {$audioCount} 个 Packet\n";
- flush();
- }
- }
- $result = pclose($handle);
- echo "音频 Packet 读取完成,数量:{$audioCount}\n";
- }
- echo "\n全部检测完成。\n";
- echo "视频异常:{$videoErrors}\n";
- echo "音频异常:{$audioErrors}\n";
复制代码
|
|