使用python查找损坏的视频



我有庞大的视频数据集(大约500000个16帧长的剪辑(。一些视频会产生类似的信息

[mpeg4 @ 0x561b46a44b80] marker does not match f_code
[mpeg4 @ 0x561b480c0740] Error at MB: 4718
[mpeg4 @ 0x561b4811b640] header damaged

我想找出导致问题的视频
我第一次尝试这个https://superuser.com/questions/100288/how-can-i-check-the-integrity-of-a-video-file-avi-mpeg-mp4解决方案,但我在错误文件中一无所获。

我的第二个想法是读取视频的第一个图像,如果出现错误,请将文件名保存到文件中。然而,这似乎不是一条错误消息:尽管消息出现在控制台上,但read返回了success=True

然后,我尝试将文件名打印为标准错误(警告消息也在其中(,将其保存到一个文件中,并进行一些后处理以提取有问题的视频。

import os
from tqdm import tqdm
import sys
folder = '/path/to/videos'
for f in tqdm(os.listdir(folder)):
sys.stderr.write('BEFORE VIDCAP ' + f + 'n')
vidcap = cv2.VideoCapture(os.path.join(folder,f))
sys.stderr.write('BETWEEN VIDCAP AND SUCCESS' + f + 'n')
success, image = vidcap.read()
sys.stderr.write('AFTER SUCCESS ' + f + 'n')

但是,标准错误按以下顺序输出:

AFTER SUCCESS
[mpeg ...] 
[mpeg ...]
...
BEFORE VIDCAP

它怎么会按照这个顺序发生是没有意义的,一些破碎的视频应该在之前和之后的某个地方看到。(如果我试着单独打开,后面或前面的也不会坏。(

我的最后一个想法是为每个视频创建一个文件,将其作为stderr并检查非空文件。(我知道它效率低得离谱,但我没有其他想法。(

for f in os.listdir(folder):
sys.stderr = open(f + '.txt', 'w')
vidcap = cv2.VideoCapture(os.path.join(folder,f))
success, image = vidcap.read()

这也不起作用,所有的错误文件都是空的,尽管消息仍然显示在标准错误中。


所以我的问题如下:

  1. 这个问题的有效解决方案是什么
  2. 这种输出顺序(第一个代码示例(是如何实现的?引擎盖下面有一些平行
  3. 如果不是标准错误(第二个代码示例(,这些消息将何去何从?如果是,为什么将它们打印到控制台而不是指定的错误文件

我同意@Christoph Rackwitz的观点,opencv不是正确的工具。你需要自己运行ffmpeg。pyav可能会给你一个更好的控制,但以下是我对ffmpeg的处理方法。

  1. 对于这个问题,什么是有效的解决方案

运行ffmpeg(使用subprocess.run(将文件解码到stdout,stdout映射到一个空管道。同时,设置stderr(文本(管道,以便捕获所有日志消息。您可以检查subprocess.run输出的returncode。如果它为非零,则该视频会出现严重错误,导致无法读取整个文件。如果为零,则可以扫描stderrstr以查找上述错误消息。不幸的是,您需要事先知道所有错误,因为会有很多[mpeg4 ...行。

这是我所能想到的最有效的解决方案。

  1. 这种输出顺序(第一个代码示例(如何可能?引擎盖下面有一些平行

取决于opencv如何使用ffmpeg。它可以捕获所有的ffmpeg日志消息,并且只在处理完文件后才显示它们。

  1. 如果不是标准错误(第二个代码示例(,这些消息会去哪里?如果是,为什么将它们打印到控制台而不是指定的错误文件

这与以上两个答案有关。opencv正在调用ffmpeg作为子进程,并且它可能正在捕获ffmpeg子进程的stderr

如果你不想学习如何运行ffmpeg,你可以试试我的ffmpegio库(pip install ffmpegio-core,如果你已经在使用NumPy,你也可以做pip install ffmpegio(,并尝试以下代码:

import ffmpegio
import os
out = ffmpegio.ffmpegprocess.run(
{"inputs": [(filename, None)], 
"outputs": [(os.devnull, {"f": "rawvideo"})]},
overwrite=True,
capture_log=True,
)
print(out.returncode)
print(out.stderr)

请注意,在它读取完文件之前会有很长一段时间的停顿。如果您想查看进度,可以使用progress选项。

如果您需要更具体的帮助,请发表评论

这是我尝试过的解决方案。

import av
from rich.progress import track
for vid in track(df.video_id):
try:
with av.open(vid) as container:
stream = container.streams.video[0]
average_fps = int(stream.average_rate)
except:

print(vid)
os.remove(vid)

相关内容

  • 没有找到相关文章

最新更新