0

尝试使用 .net 上的 ImageMagick 库对帧进行一些操作(调整大小+与其他图像组合),但面临不正确的“重新组装”视频,输出视频带有一些伪影。

因此,作为 mp4 短文件的示例,我们有:mp4 (130kb):https ://c2n.me/4eU1Twz.mp4

第一帧是:在此处输入图像描述 第二帧是:在此处输入图像描述

以及所有具有类似伪影的下一帧。

获取帧并将它们保存到磁盘的代码:

string incomingFilePath = AppContext.BaseDirectory + "test.mp4";                   

using (var videoFrames = new MagickImageCollection(incomingFilePath, MagickFormat.Mp4))
{                        
        for (var i = 0; i < _incomingImageFrames.Count; i++)
        {
            _incomingImageFrames[i].Write(AppContext.BaseDirectory + Guid.NewGuid() + ".png");
        }
}

如果我试图将图像“重新组合”到 mp4(进行一些修改,使用 compose() 方法等),我会得到带有伪像的视频。来自输出 .mp4 的样本:

所以需要以某种方式修复它,但不知道为什么。有人可以帮我吗?

在此处输入图像描述

4

1 回答 1

0

原因在于 mp4/h.264 编解码器的“性质”。第一帧总是“满的”,而所有其他帧 - 是当前帧和前一帧之间的区别,所以据我所知,当 mp4 尝试“组装”而不是原始图像(修改)时 - ffmpeg 试图做到最好并将它们全部粘合到视频。

所以作为一种解决方法——我们可以在运行时删除这个帧差异,然后再将它们转发到 ffmpeg 引擎。

在 ImageMagick 的情况下,我们需要在组装之前将当前帧与之前的帧合成以获得“完整绘制的帧”作为结果。

示例代码:

string incomingFilePath = AppContext.BaseDirectory + "test.mp4";                   
    
    using (var videoFrames = new MagickImageCollection(incomingFilePath, MagickFormat.Mp4))
    {
            var _resultImageCollection = new MagickImageCollection(); //temp collection
            var prevFullFrame = _incomingImageFrames.First(); //save last full frame, as initial it will be first in collection
            for (var i = 0; i < _incomingImageFrames.Count; i++)
            {
                prevFullFrame.Composite(_incomingImageFrames[i],_incomingImageFrames[i].Page.X, _incomingImageFrames[i].Page.Y, CompositeOperator.Over); //combining previous (full frame) with current (with partial filled pixels)
                _resultImageCollection.add(prevFullFrame); //adding to result collection
            }
            _resultImageCollection.Write(AppContext.BaseDirectory + "result.mp4"); //assembling mp4
    }

从性能方面来看,也许不是最好的,但效果很好。此外,它会增加一些尺寸,但不会显着增加。在我的情况下,它大约是 +10%,所以可以接受。(36Kb 与 40Kb)

更新:如果您在保存前调用 Optimize() 进行收集,它将具有相同的大小。

_resultImageCollection.Optimize();

也许有人知道更好的解决方案?

于 2022-02-11T00:38:29.010 回答