2

我有一些.ts文件和相应的index.m3u8文件,看起来像这样:

#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:15
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:3.170,
seg-1-v1-a1.ts
#EXTINF:3.170,
seg-2-v1-a1.ts
#EXTINF:3.170,
seg-3-v1-a1.ts
#EXTINF:3.170,
seg-4-v1-a1.ts
#EXTINF:3.170,
seg-5-v1-a1.ts
#EXT-X-ENDLIST

因此,要将其转换为单个output.mp4文件,我运行了以下命令:

$ ffmpeg -i index.m3u8 -c copy output.mp4
...
[hls @ 0x55d78a3a6280] Opening 'seg-1-v1-a1.ts' for reading
...
[hls @ 0x55d78a3a6280] Opening 'seg-2-v1-a1.ts' for reading
[hls @ 0x55d78a3a6280] Opening 'seg-3-v1-a1.ts' for reading
[hls @ 0x55d78a3a6280] Opening 'seg-4-v1-a1.ts' for reading
[hls @ 0x55d78a3a6280] Opening 'seg-5-v1-a1.ts' for reading
...

之后,我删除了.ts文件,index.m3u8并且只保留了output.mp4. 然而,事实证明,我没有所有.ts文件,输出最初更像这样:

$ rm seg-3-v1-a1.ts
$ ffmpeg -i index.m3u8 -c copy output.mp4
...
[hls @ 0x5555d0d86280] Opening 'seg-1-v1-a1.ts' for reading
...
[hls @ 0x5555d0d86280] Opening 'seg-2-v1-a1.ts' for reading
[hls @ 0x5555d0d86280] Opening 'seg-3-v1-a1.ts' for reading
[hls @ 0x5555d0d86280] Failed to open segment 3 of playlist 0
[hls @ 0x5555d0d86280] Opening 'seg-4-v1-a1.ts' for reading
[hls @ 0x5555d0d86280] Opening 'seg-5-v1-a1.ts' for reading
...

观看视频时,在缺失片段的位置,画面冻结几秒钟,然后视频继续播放。我有几个.mp4文件,我想找出其中哪些文件受到此问题的影响。在没有原始日志的情况下,如何在运行ffmpeg -i index.m3u8 -c copy output.mp4命令时找出是否缺少任何段?

我在https://superuser.com/questions/100288/how-can-i-check-the-integrity-of-a-video-file-avi-mpeg-mp4找到了一个命令,不幸的是没有发现任何问题:

$ ffmpeg -v error -i output.mp4 -f null -
$ echo $?
0
4

1 回答 1

1

您可以检查 r_frame_rate 和 avg_frame_rate 是否相等。
下面的命令:

ffprobe -v error -show_streams output.mp4 | grep "frame_rate"

将输出(对于正确的文件)是这样的:

r_frame_rate=24/1
avg_frame_rate=24/1

和(对于损坏的文件)是这样的:

r_frame_rate=24/1
avg_frame_rate=886/37

这种方法并不完美,但在很多情况下应该完全没问题。


第二种方法,直观且在我看来仅在特定条件下工作,正在寻找冻结。例如:

ffmpeg -i output.mp4 -vf "freezedetect=n=-60dB:d=2" -f null - 1>/dev/null 2>&1 \
| grep "duration"

它可以工作,但前提是流确实是特定的。


另一种方法,类似于第一种方法,是寻找 VFR。
命令:

ffmpeg -i output.mp4 -vf vfrdet -an -f null -

将输出:

[Parsed_vfrdet_0 @ 0x55563547bf00] VFR:0.000094 (2/21261) 最小值:3750 最大值:183750 平均值:93750

对于损坏的文件。为了正确,它将是:

[Parsed_vfrdet_0 @ 0x564c33d53140] VFR:0.000000 (0/21311)

这与第一种方法相似,但与外表相反——不同!
据我所知,r_frame_rate和是可能的avg_frame_rate,而 VFR 不为零!

在我看来,检查 VFR 是最好的选择,并且可能会奏效。很糟糕,您没有提供任何示例文件。我假设您的流应该有 VFR:0.000000,但那是在阅读茶叶。

据我所知,没有通用的方法可以满足您的需求。我希望我的任何示例都适合,但它确实取决于并且需要在实践中在正确的文件上进行测试。正是这些,您要检查。


根据您在我的回答下方的回复,我已经实现了简单的脚本:

  1. 下载ts文件
  2. 将这些转换为正确的 mp4
  3. 损坏 ts 文件之一
  4. 将这些(缺少 ts 文件)转换为损坏的 mp4
  5. 使用我的第一种方法测试每个 mp4 文件(比较 r_frame_rate == avg_frame_rate)
#!/usr/bin/bash

# Blender demo movie https://en.wikipedia.org/wiki/Sintel
# Full URL: https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8

bURL=https://bitdash-a.akamaihd.net/content/sintel/hls/video/

# I'm checking each available bitrate. You can modify that.
bitratesArray=("250" "500" "800" "1100" "1500" "4000" "6000" "10000")

# Here you can choose which ts file you want to remove from
# the ffmpeg conversion (it'll be temporary renamed, doesn't matter).
tsToCorrupt="14"

for i in ${bitratesArray[@]}
do
  # Download all files.
  # To be nice, I'm preventing unnecessary server load.
  if [ ! -d "${i}kbit" ]
  then
    echo -e "\nDownloading ${i}kbit version"
        
    curl "${bURL}${i}kbit.m3u8" | tee -a "${i}kbit.m3u8" | grep '\.ts' | \
    sed -e "s|^|$bURL|g" -e "s/\.ts/\.ts /g" > "${i}kbit_fullURL.m3u8"
        
    aria2c -q -c -j 16 -x 16 -d "${i}kbit" -i"${i}kbit_fullURL.m3u8"
    echo -e "\n"
  fi
    
  # Convert proper
  echo "Converting: ${i}kbit_proper.mp4" 
  ffmpeg -y -hide_banner -loglevel error \
  -i "${i}kbit.m3u8" -c copy "${i}kbit_proper.mp4" 
    
  # Make temporal source defect
  mv "${i}kbit/seq-${tsToCorrupt}.ts" "${i}kbit/seq-${tsToCorrupt}.ts_CORRUPTED"
    
  # Convert defective
  echo "Converting: ${i}kbit_defective.mp4" 
  ffmpeg -y -hide_banner -loglevel error \
  -i "${i}kbit.m3u8" -c copy "${i}kbit_defective.mp4" 
    
  # Repair defected source (obviously converted file is still corrupted)
  mv "${i}kbit/seq-${tsToCorrupt}.ts_CORRUPTED" "${i}kbit/seq-${tsToCorrupt}.ts"
done

# Examine generated files
echo -e "\n\nREPORT"
for i in *.mp4
do
  echo -e "\n---------------------------\nFilename: \n${i}"

  report=$(ffprobe -v error -show_streams $i | grep "frame_rate")

  echo -e "\ncalculated frame rates:\n${report}"
    echo -e "\nVerdict: \nFile ${i} is "

  echo ${report} | \
  awk -F'[=\n ]' ' { if ( $2 == $4 ) { print "OK" } else { print "WRONG" }; } ' 
done

对我来说,它工作正常。

于 2021-12-30T03:09:58.943 回答