我有一部电影的两个副本,两个副本都有一些损坏,但损坏的位置不同。两个电影都可以播放,但会在不同位置跳过不同的帧。
有没有办法将这些电影文件合并(例如ffmpeg
)从两个文件中取出“好帧”并将它们合并为一个新文件,从而至少保留大部分电影?
有没有办法从两部电影中只导出可读的帧,并用一部电影的工作帧进行补充?
另外(或者另外),我可以对损坏的电影文件重新编码,但只留下可读的帧吗?
在我看来,这听起来像是人工智能的完美工作:阅读视频,找出哪些帧损坏了,然后根据人工智能所知道的(或假设的)计算出那些丢失的帧。也许有一天会实现。
我在 Ventura 13.4.1 下的 macOS 上工作。
答案1
初步说明
- 这个答案介绍了一种合并两个或多个损坏文件的方法曾经是相同的,但在不同的碎片中遭受了腐烂。
- 该方法具有通用性,并不局限于视频文件。
- 问题提到了两个副本。这个答案是通用的,假设有两个或多个副本,可能(但不一定)位于不同的文件系统上。
- 存在与保存文件的文件系统相关的情况。
- 不能保证该方法一定有效(请参阅最后的“结论”)。
健康)状况
该方法要求保存文件的文件系统在您尝试读取损坏的部分时抛出读取错误。来自不会抛出读取错误的文件系统的一份副本可以作为最后的手段,但必须先使用来自会抛出读取错误的文件系统的至少一份副本。
为什么会出现这种情况以及它意味着什么
请注意,以前播放正常的视频文件可能以两种不同的方式损坏:
有些片段因某种原因而发生变化,有些位被翻转,但文件系统认为文件是健康的。损坏仅在以下情况下才会显现:内部结构由程序解释,程序可以理解它们并期望它们遵循某些规范。对于视频文件,程序可能是一个播放器,它会告诉你某些帧已损坏;对于 PDF 文件,程序可能是一个 PDF 阅读器;等等。但对于不关心内部结构的程序来说,以这种方式损坏的文件看起来是正常的:
cat >/dev/null
将读取整个文件,cp
复制它,base64
对其进行编码,md5sum
计算一些总和,od
向您显示八进制字节;所有这些沒有任何錯誤。损坏的碎片是因为底层块设备根本无法读取某些数据(严重划伤的 CD 或 DVD;有坏扇区的 HDD),或者因为文件系统以某种方式知道块设备上的某些数据是坏的(例如Btrfs 在读取时验证校验和)。您会收到读取错误。请注意,对于视频文件,您的播放器可能会(也可能不会)忽略错误,跳过帧,因此实际上它可能将这种损坏视为另一种损坏(如上所述);但像
cat
或这样的工具cp
将要第一个错误就停止。
为了使这个答案有效,我们希望所有损坏都伴有读取错误。判断是否存在至少一个读取错误的简单方法是读取文件:cat the_file >/dev/null
。如果此命令没有抛出您知道(“内部”)损坏的文件的读取错误,则该文件只能作为最后的手段(稍后将对此进行解释)。如果此命令抛出读取错误,那么您可能希望文件内的所有损坏都伴有读取错误。
请注意,可能会发生文件内某些损坏伴随读取错误的情况,而文件其他地方的损坏是“内部的”,不伴随读取错误。在这里我们认为如果发生读取错误,那么我们很幸运,所有损坏都伴随着读取错误。
程序
这是我的另一个答案提供了一个命令来尽可能多地读取文件(文件系统会抛出读取错误)。选择文件系统会抛出读取错误的副本并运行以下命令:
ddrescue /path/to/copy1 /where/to/save/result mapfile
如果result
和mapfile
尚不存在,该工具将创建这些文件。观察输出;它应该会告诉你有一些读取错误。命令完成后,你可以检查mapfile
并看到数据块列表-
包含具有状态(或使用)的行ddrescueview
。
然后继续进行文件系统抛出读取错误的下一个副本:
ddrescue /path/to/copy2 /where/to/save/result mapfile
其中result
和mapfile
是上次运行 的准确文件ddrescue
。该工具将尝试填补空白,即在读取 后,mapfile
它将知道 的哪些部分copy1
未到达result
(由于读取错误),并且它将尝试从 读取它们copy2
。
再次观察输出并检查mapfile
。可能需要的某些部分copy2
无法读取;如果是这样,请尝试从 读取copy3
,copy4
依此类推。所有这些副本都应来自报告读取错误的文件系统。
除非底层块设备中的一个或多个即将在硬件层面上死机,否则读取副本的顺序并不重要。如果您怀疑某些块设备即将发生故障,那么明智的做法是先从健康的设备读取,也许您根本不需要从不健康的设备读取。
希望最终ddrescue
会告诉您文件已 100% 恢复,您可以通过检查 来确认这一点mapfile
,您将在数据块列表中找到一行,状态为+
。如果发生这种情况,那么您可以确定 的每个片段result
都是从副本中读取的,并且该特定片段不会引发读取错误;因此result
应该是一个正确的文件(假设没有伴随读取错误的损坏)。
如果ddrescue
救援率低于 100% 怎么办?
如果读取所有副本(其中损坏伴随读取错误)后仍有空白需要填补(状态-
为mapfile
),则有以下几种选择:
如果没有更多副本(即没有副本的损坏不伴有读取错误),那么您根本无法填补空白。您已经尝试了所有副本,它们都在同一个片段中报告了读取错误,因此无处可从中获取丢失的数据。
如果只有一个副本的损坏没有伴随读取错误,则将该副本
ddrescue
作为最后的手段。该工具将填补空白并或许上次复制的数据不会被这些精确的碎片“内部”损坏,而result
会成为一个正确的文件。如果有两个或多个副本的损坏没有伴随读取错误,那么您可以使用它们中的每一个分别地以
ddrescue
作为最后的手段。“分别”意味着您应该尝试使用 和 的单独副本对每个此类文件进行尝试result
。mapfile
对于 的每个副本,result
该工具将使用不同的文件填补空白,并或许至少在一种情况下,文件中的数据不会被这些精确的片段“内部”损坏,而result
会成为一个正确的文件。
如果出现损坏但未伴随读取错误会怎样?
一些可能的情况:
- 损坏且未伴随读取错误的文件就是您所拥有的一切。
ddrescue
读取所有伴有读取错误的损坏文件,但仍存在空白;并且您有两个或多个没有读取错误的文件,但是它们中的任何一个都不足以填补所有空白并生成正确的文件。- 认为文件的一次读取错误意味着文件中的所有损坏都伴随着读取错误的假设是错误的。
在这些和类似情况下,您需要一个能够理解文件内部结构并能够检测不伴随读取错误的损坏的工具。对于视频文件,这将是一些视频编辑软件;因此这将是您明确询问的内容。此答案不涵盖这种情况。
结论
根据具体情况,该方法可能有效,也可能无效。
如果您可以读取所有副本而没有读取错误,则该方法无效。
如果至少有一个副本出现读取错误,那么就有可能所有损坏都伴随着读取错误,您可以通过读取其他副本(或多个副本)来填补空白;该方法可能有效。
该方法似乎有效(即
ddrescue
可能告诉您它恢复了 100% 的文件),但实际上却无效(即文件仍然“内部”损坏,例如视频文件仍然包含无效帧)。这是因为可能存在不伴随读取错误的损坏。我们假设情况并非如此,但实际上可能如此。
如果至少有一份副本出现读取错误,那么您应该尝试该方法,也许它会起作用。