我有庞大的视频数据集(大约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()
这也不起作用,所有的错误文件都是空的,尽管消息仍然显示在标准错误中。
所以我的问题如下:
- 这个问题的有效解决方案是什么
- 这种输出顺序(第一个代码示例(是如何实现的?引擎盖下面有一些平行
- 如果不是标准错误(第二个代码示例(,这些消息将何去何从?如果是,为什么将它们打印到控制台而不是指定的错误文件
我同意@Christoph Rackwitz的观点,opencv不是正确的工具。你需要自己运行ffmpeg。pyav
可能会给你一个更好的控制,但以下是我对ffmpeg的处理方法。
- 对于这个问题,什么是有效的解决方案
运行ffmpeg(使用subprocess.run
(将文件解码到stdout,stdout映射到一个空管道。同时,设置stderr(文本(管道,以便捕获所有日志消息。您可以检查subprocess.run
输出的returncode
。如果它为非零,则该视频会出现严重错误,导致无法读取整个文件。如果为零,则可以扫描stderr
str以查找上述错误消息。不幸的是,您需要事先知道所有错误,因为会有很多[mpeg4 ...
行。
这是我所能想到的最有效的解决方案。
- 这种输出顺序(第一个代码示例(如何可能?引擎盖下面有一些平行
取决于opencv
如何使用ffmpeg。它可以捕获所有的ffmpeg日志消息,并且只在处理完文件后才显示它们。
- 如果不是标准错误(第二个代码示例(,这些消息会去哪里?如果是,为什么将它们打印到控制台而不是指定的错误文件
这与以上两个答案有关。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)