在保留帧率的同时将animationgif转换成Linux服务器上的video

如何在Linux服务器上以编程方式将animationgif转换为video(例如h264 @ mp4)?

我需要这个处理用户生成的内容,应该输出为几个定义的video格式; 因此它的可能,用户可能想要处理animationgif文件。 我已经有一套工作的PHP脚本,使用avconv将video文件转换为特定格式(如vpx @ webm和h264 @ mp4,缩放到特定的分辨率),但是因此我需要videoinput。

通常的方式似乎是提取GIF的帧,然后编码,如

convert file.gif file%03d.png avconv -i file%03d.png file.mp4 

但是这会丢弃由gif文件中的暂停信息确定的帧速率。 它有可能用-r定义一个帧率到avconv,但是

  • 这不考虑帧之间的暂停,因为它们可以不同(如第一帧100ms暂停,第二帧250ms暂停,第三帧100ms暂停,…)
  • 作为input来自用户,它甚至可能会有所不同,因为一些gif可能有5fps和其他30fps

我注意到,avconv能够自己处理GIF,因此可以尊重正确的暂停,但是当我这样做(就像在如何将GIF转换为Mp4中描述的那样? )

 avconv -i file.gif -r 30 file.mp4 

avconv只会采取gif的第一帧,而它检测到的文件至less是video:

 Duration: 00:00:00.04, start: 0.000000, bitrate: N/A Stream #0.0: Video: gif, pal8, 640x480, 25 tbn 

(例如gif'file.gif'有15个帧,每个都有100ms的暂停=> 1.5s的持续时间,循环)

  • 我错过了什么? 怎么了?
  • 这个用例可能有更好的工具吗?
  • 什么是大的网站,如9gag使用转码上传的GIFvideo?

另一个Avconv错误(YAAB)

ffmpeg有更好的GIF demux支持(和改进的GIF编码 )。 我建议avconvffmpeg (FFmpeg的真正的;而不是从Libav旧的骗子)。 静态构建很容易,或者你当然可以编译 。

 ffmpeg -i in.gif -c:v libx264 -pix_fmt yuv420p -movflags +faststart out.mp4 

有关更多示例,请参阅FFmpeg Wiki:H.264编码指南 。

如果由于某种原因,你需要使用avconv和imagemagick,你可能想尝试这样的事情:

 ticks_per_frame = subprocess.check_output('identify -verbose -format %T_ {0}'.format(gif_path).split()).split('_')[:-1] ticks_per_frame = [int(i) for i in ticks_per_frame] num_frames = len(ticks_per_frame) min_ticks = min(ticks_per_frame) subprocess.call('convert -coalesce {0} tmp%d.png'.format(gif_path).split()) if len(set(ticks_per_frame)) > 1: num_dup = 0 num_dup_total = 0 for frame, ticks in enumerate(ticks_per_frame): num_dup_total += num_dup frame += num_dup_total num_dup = 0 if ticks > min_ticks: num_dup = (ticks / min_ticks) - 1 for i in range(num_frames + num_dup_total - 1, frame, -1): orig = 'tmp%d.png' % i new = 'tmp%d.png' % (i + num_dup) subprocess.call(['mv', orig, new]) for i in range(1, num_dup + 1): curr = 'tmp%d.png' % frame dup = 'tmp%d.png' % (i + frame) subprocess.call(['cp', curr, dup]) framerate = (100 / min_ticks) if min_ticks else 10 subprocess.call('avconv -r {0} -i tmp%d.png -c:v libx264 -crf {1} -pix_fmt yuv420p \ -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 -y {2}.mp4'.format(framerate, quality, STORAGE_DIR + mp4_name).split()) subprocess.call(['rm'] + glob('tmp*.png')) 

因此,获取GIF的每一帧(通过识别)的厘秒数,转换为多个PNG,然后根据刻度值进行复制。 你不用担心,PNG文件将保持连续的顺序。 使用真正的FFmpeg仍然是最好的选择。