[postprocessor:ugoira] insert extra frame
into files generated with the 'image2' demuxer to compensate for the last frame not being shown for as long as it should. This only happens for ugoira with non-uniform delays between frames and only when 'repeat-last-frame' is enabled.
This commit is contained in:
@@ -10,12 +10,20 @@
|
|||||||
|
|
||||||
from .common import PostProcessor
|
from .common import PostProcessor
|
||||||
from .. import util
|
from .. import util
|
||||||
import collections
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
import shutil
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
from math import gcd
|
||||||
|
except ImportError:
|
||||||
|
def gcd(a, b):
|
||||||
|
while b:
|
||||||
|
a, b = b, a % b
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
class UgoiraPP(PostProcessor):
|
class UgoiraPP(PostProcessor):
|
||||||
|
|
||||||
@@ -151,10 +159,26 @@ class UgoiraPP(PostProcessor):
|
|||||||
|
|
||||||
def _process_image2(self, pathfmt, tempdir):
|
def _process_image2(self, pathfmt, tempdir):
|
||||||
tempdir += "/"
|
tempdir += "/"
|
||||||
|
frames = self._frames
|
||||||
|
|
||||||
|
# add extra frame if necessary
|
||||||
|
if self.repeat and not self._delay_is_uniform(frames):
|
||||||
|
last = frames[-1]
|
||||||
|
delay_gcd = self._delay_gcd(frames)
|
||||||
|
if last["delay"] - delay_gcd > 0:
|
||||||
|
last["delay"] -= delay_gcd
|
||||||
|
|
||||||
|
self.log.debug("non-uniform delays; inserting extra frame")
|
||||||
|
last_copy = last.copy()
|
||||||
|
frames.append(last_copy)
|
||||||
|
name, _, ext = last_copy["file"].rpartition(".")
|
||||||
|
last_copy["file"] = "{:>06}.{}".format(int(name)+1, ext)
|
||||||
|
shutil.copyfile(tempdir + last["file"],
|
||||||
|
tempdir + last_copy["file"])
|
||||||
|
|
||||||
# adjust frame mtime values
|
# adjust frame mtime values
|
||||||
ts = 0
|
ts = 0
|
||||||
for frame in self._frames:
|
for frame in frames:
|
||||||
os.utime(tempdir + frame["file"], ns=(ts, ts))
|
os.utime(tempdir + frame["file"], ns=(ts, ts))
|
||||||
ts += frame["delay"] * 1000000
|
ts += frame["delay"] * 1000000
|
||||||
|
|
||||||
@@ -228,11 +252,26 @@ class UgoiraPP(PostProcessor):
|
|||||||
file.write("\n".join(content))
|
file.write("\n".join(content))
|
||||||
return timecodes
|
return timecodes
|
||||||
|
|
||||||
|
def calculate_framerate(self, frames):
|
||||||
|
uniform = self._delay_is_uniform(frames)
|
||||||
|
if uniform:
|
||||||
|
return ("1000/{}".format(frames[0]["delay"]), None)
|
||||||
|
return (None, "1000/{}".format(self._delay_gcd(frames)))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calculate_framerate(framelist):
|
def _delay_gcd(frames):
|
||||||
counter = collections.Counter(frame["delay"] for frame in framelist)
|
result = frames[0]["delay"]
|
||||||
fps = "1000/{}".format(min(counter))
|
for f in frames:
|
||||||
return (fps, None) if len(counter) == 1 else (None, fps)
|
result = gcd(result, f["delay"])
|
||||||
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _delay_is_uniform(frames):
|
||||||
|
delay = frames[0]["delay"]
|
||||||
|
for f in frames:
|
||||||
|
if f["delay"] != delay:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
__postprocessor__ = UgoiraPP
|
__postprocessor__ = UgoiraPP
|
||||||
|
|||||||
Reference in New Issue
Block a user