diff --git a/docs/configuration.rst b/docs/configuration.rst index fbd1da50..8006d989 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -2498,6 +2498,18 @@ Description Additional FFmpeg command-line arguments. +ugoira.ffmpeg-demuxer +--------------------- +Type + ``string`` +Default + ``image2`` +Description + FFmpeg demuxer to read input files with. Possible values are + "`image2 `_" and + "`concat `_". + + ugoira.ffmpeg-location ---------------------- Type diff --git a/gallery_dl/postprocessor/ugoira.py b/gallery_dl/postprocessor/ugoira.py index e8a2c591..86d0f620 100644 --- a/gallery_dl/postprocessor/ugoira.py +++ b/gallery_dl/postprocessor/ugoira.py @@ -34,6 +34,11 @@ class UgoiraPP(PostProcessor): if rate != "auto": self.calculate_framerate = lambda _: (None, rate) + if options.get("ffmpeg-demuxer") == "concat": + self._process = self._concat + else: + self._process = self._image2 + if options.get("libx264-prevent-odd", True): # get last video-codec argument vcodec = None @@ -72,38 +77,17 @@ class UgoiraPP(PostProcessor): if not self._frames: return - rate_in, rate_out = self.calculate_framerate(self._frames) - with tempfile.TemporaryDirectory() as tempdir: # extract frames try: with zipfile.ZipFile(pathfmt.temppath) as zfile: zfile.extractall(tempdir) except FileNotFoundError: - pathfmt.temppath = pathfmt.realpath + pathfmt.realpath = pathfmt.temppath return - # write ffconcat file - ffconcat = tempdir + "/ffconcat.txt" - with open(ffconcat, "w") as file: - file.write("ffconcat version 1.0\n") - for frame in self._frames: - file.write("file '{}'\n".format(frame["file"])) - file.write("duration {}\n".format(frame["delay"] / 1000)) - if self.extension != "gif": - # repeat the last frame to prevent it from only being - # displayed for a very short amount of time - file.write("file '{}'\n".format(self._frames[-1]["file"])) - - # collect command-line arguments - args = [self.ffmpeg] - if rate_in: - args += ("-r", str(rate_in)) - args += ("-i", ffconcat) - if rate_out: - args += ("-r", str(rate_out)) - if self.prevent_odd: - args += ("-vf", "crop=iw-mod(iw\\,2):ih-mod(ih\\,2)") + # process frames and collect command-line arguments + args = self._process(tempdir) if self.args: args += self.args self.log.debug("ffmpeg args: %s", args) @@ -112,7 +96,7 @@ class UgoiraPP(PostProcessor): pathfmt.set_extension(self.extension) try: if self.twopass: - if "-f" not in args: + if "-f" not in self.args: args += ("-f", self.extension) args += ("-passlogfile", tempdir + "/ffmpeg2pass", "-pass") self._exec(args + ["1", "-y", os.devnull]) @@ -131,6 +115,45 @@ class UgoiraPP(PostProcessor): else: pathfmt.set_extension("zip") + def _concat(self, path): + # write ffconcat file + ffconcat = path + "/ffconcat.txt" + with open(ffconcat, "w") as file: + file.write("ffconcat version 1.0\n") + for frame in self._frames: + file.write("file '{}'\n".format(frame["file"])) + file.write("duration {}\n".format(frame["delay"] / 1000)) + if self.extension != "gif": + # repeat the last frame to prevent it from only being + # displayed for a very short amount of time + file.write("file '{}'\n".format(frame["file"])) + + rate_in, rate_out = self.calculate_framerate(self._frames) + args = [self.ffmpeg, "-f", "concat"] + if rate_in: + args += ("-r", str(rate_in)) + args += ("-i", ffconcat) + if rate_out: + args += ("-r", str(rate_out)) + return args + + def _image2(self, path): + path += "/" + + # adjust frame mtime values + ts = 0 + for frame in self._frames: + os.utime(path + frame["file"], ns=(ts, ts)) + ts += frame["delay"] * 1000000 + + return [ + self.ffmpeg, + "-f", "image2", + "-ts_from_file", "2", + "-pattern_type", "sequence", + "-i", path.replace("%", "%%") + "%06d.jpg", + ] + def _exec(self, args): out = None if self.output else subprocess.DEVNULL return subprocess.Popen(args, stdout=out, stderr=out).wait()