如何在ffmpeg中将jpg图像序列无损编码为视频?


21

我有大量的jpg图片,希望将它们无损地转换为视频(或者,至少,只要编码时间不比其他时间长很多,就非常接近无损地)。

天真的,我认为应该有一些编解码器可以按原样存储每个单独的jpg帧(无需重新压缩),并且也许可以通过仅用前一帧的增量信息替换某些帧来实现一些不错的压缩。在我的情况下,有许多帧序列彼此相同,或者它们之间的差别很小。

ffmpeg是否有一些编解码器和合适的设置可以实现这一目标?




1
jpeg序列已经很长时间了。我认为,不使用h.264的数码相机总是记录MJPEG,而视频捕捉卡则使用它。
彼得·科德斯

Answers:


24

只是混合图像

您只需将JPG图像多路复用即可制作视频:

ffmpeg -framerate 30 -i input%03d.jpg -codec copy output.mkv

请注意,如果省略,-framerate则默认值-framerate 25将应用于输入。

无损优化

您可以用来jpegtran对每个帧执行无损优化,这可以节省大量文件:

mkdir outputdir
for f in *.jpg; do jpegtran -optimize -copy none -perfect -v "$f" > "outputdir/$f"; done

现在与ffmpeg上面所示的多路复用。

检查它实际上是无损的

framehash复用器可以用来比较每个帧的唯一哈希值,以确保结果是真正的无损:

$ ffmpeg -i input%03d.jpg -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

$ ffmpeg -i output.mkv -map 0:v -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

在以上示例中,输入和输出的每个关联帧共享相同的哈希值,以确保帧相同且输出无损。

另见


您能否阐明这两个framemd5命令除了列出哈希值之外还应该实现什么?这样确定相同的帧后,如何获得额外的压缩?
GJ。

1
包含这些哈希值只是为了向您显示这些帧与单个图像相同,因此可以满足您“按原样存储每个jpg帧(无需重新压缩)”的要求。
llogan

发布了我自己的答案,其中包含删除重复帧的未经测试的想法,最后得到了VFR MJPEG.mkv。VFR是我想到的唯一利用MJPEG的时间冗余的方法。:P
彼得·科德斯

SSIM可能是比较保真度的更快方法。
Gyan

11

这将输出无损的H.264视频,其中帧将使用其他帧中的信息

ffmpeg -f image2 -r 30 -i %09d.jpg -vcodec libx264 -profile:v high444 -refs 16 -crf 0 -preset ultrafast a.mp4

选项说明:

  • -f image2 -告诉ffmpeg选择一组图像
  • -r 30 -告诉ffmpeg以每秒30帧(或图像)的速度编码(将其更改为所需的帧率)
  • -i %09d.jpg-告诉ffmpeg使用图像000000000.jpg至999999999.jpg作为输入。更改9%09d.jpg有多少个零的图像序列的名字了。如果您的文件名是例如img0001.jpg,则它将表示为img%04d.jpg
  • -vcodec libx264 -告诉ffmpeg输出到H.264兼容文件
  • -profile:v high444 -告诉libx264使用高4:4:4预测无损配置文件,允许无损编码
  • -refs 16 -告诉libx264将16张图像存储在缓冲区中,以便视频中的其他图像可以引用它们
  • -crf 0 -告诉libx264执行无损编码
  • -preset ultrafast -告诉libx264将编码速度优先于输出文件大小
  • a.mp4-告诉ffmpeg将输出保存在名为a.mp4的MP4文件中。将此更改为您要使用的文件名和格式

3
一些注意事项:-f image2这里是多余的。该图像文件分路器应使用-framerate来代替-r。libx264将自动选择适当-profile的无损格式,-preset并将处理-refs
llogan'1

-refs 5在MOST,除非您知道您的内容具有相同的图像,并用其他图像分开,否则可能会导致x264在到达重复项之前丢失引用。高于ultrafast使得无损模式略有不同,比CABAC的约10%的涨幅比CAVLC(在无损所需要的比特率较高的CPU成本)等。严重的是,在一些实况转播的720x480p60(去隔行输出)上,容量superfast为28GB,slower容量为27GB。如果编码时间无关紧要,而解码时间无关紧要,请确保避免使用CABAC。甚至可能-tune fastdecode。适中的引用计数不应该受到影响。
彼得·科德斯

而且,如果您有要刻录的CPU,您甚至可以尝试-preset placebo百分之几的额外费用。
DrYak

同样为了完整起见,h265还具有其自己的无损模式。-vcodec libx265 -x265-params lossless=1是等效选项。(但是以我的经验(=录制Powerpoint幻灯片演示文稿),它不一定更好,并且比h264慢得多)请继续关注明年的AOMedia的AV1 / IETF的NETVC1 / Xiph的Daala /届时将如何重命名...的无损模式
DrYak

5

您可以创建一个avi动画作为一个系列的png图像(png 无损的,因此jpeg => png转换不应降低您的图片):

如果您的图片名为 img_0001.jpg

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec png video.avi

其中“ 25”是您想要的结果视频中的帧频。-start_number如果为1,则不需要。但是如果您的第一个视频编号不是1,则很有用。

如果要以mjpeg最高质量进行编码,则命令行为:

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec mjpeg -qscale 1 video.avi

事情的好处是您可以将视频转换回一系列图片:

ffmpeg -i video.avi "img_series_%04d.png"
ffmpeg -i video.avi "img_series_%04d.jpg"

等等...


这确实不能满足发问者的需求。他正在寻找一种方法,只有在图像改变时才可以无损地更新框架。这意味着同一图像可能被多次使用。jpeg本质上也不是无损的,因为我相信它即使在最高质量下也使用jpeg压缩。
AJ Henderson

实际上,我猜他很愿意进行压缩,尽管我不确定在同一帧的长序列上该怎么做。尽管我不确定ffmpeg是否支持任何格式,但我仍然认为需要使用可变帧速率演示格式。
AJ Henderson

CorePNG也可以创建P帧。通常jpeg并不是无损压缩,我怀疑mjpeg可以创建P帧。我同意我不会回答所提出的问题,但我给出了使用ffmpeg制作无损视频的解决方案。
奥利维尔·S

4

要扩展LordNeckbeard的答案,是的,只需将JPEG数据混合到MJPEG视频流中即可。这将是输出图像精确序列的最小表示,即使MJPEG在当今的标准下效率极低。(没有时间冗余,甚至没有任何帧内预测。

您可以制作可变帧率的MJPEG视频,以利用输入中的重复图像。

ffmpeg -framerate 30 -i input%03d.jpg -vf mpdecimate -codec copy output.mkv  # doesn't work.

嗯,这是行不通的,因为mpdecimate不适用于压缩数据,并且我们不能让ffmpeg解码然后重新jpeg图像数据而不会造成损失和CPU成本。

也许如果您将重复的jpg源文件替换为具有该序列号的空文件,或者其他内容?

由于这个问题还不是最近的,除非有人回答问如何做,否则我不会花时间去弄清楚该怎么做。但是由于MJPEG可以放入mkv容器中,因此我敢肯定,有一个文件不会对重复帧重复jpeg数据,而只是没有输出帧要解码,直到重复序列被过度。

哦,这是个主意:

ffmpeg -framerate blah -input blah -vf mpdecimate -f mkvtimestamp_v2 mpdecimate.timestamps

然后删除(或移开)mpdecimate要删除的帧的所有jpeg(可能有一些日志记录选项?或-vf showinfo,然后对其进行解析,然后仅移动或硬链接显示在其输出中的帧,留在后面丢弃的JPEG?)。将其多路复用到MJPEG.mkv,然后使用mkvmerge进行一些操作,将其中的帧时间戳替换为中的时间戳mpdecimate.timestamps

如果您使用的是xcoding,而不是仅仅将jpeg数据混合到MJPEG,这将更加容易,因为您只需将我的第一个命令与mpdecimate和除以外的任何编解码器一起使用copy,它将可以正常工作(tm)。

我没有尝试过任何一个,因为这是一个老问题。这也是我没有填补如何基于mpdecimate输出实际过滤jpeg目录或如何实际使用时间戳流的空白的原因。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.