diff options
| author | Brianna Rainey | 2026-02-12 15:38:54 -0500 |
|---|---|---|
| committer | GitHub | 2026-02-12 15:38:54 -0500 |
| commit | f03a3a686c7304588dd434322c73506531e53595 (patch) | |
| tree | ee41d920873e9a77c41f4a65857af019e71a4754 /src/avp/toolkit/ffmpeg.py | |
| parent | 48a9105eab94e64101470402427564203e1d8970 (diff) | |
v2.2.4 - Quiet FFmpeg; add "invert" option to Classic Vis; fix CLI parsing for Image component (#96)
* change noisiness of terminal output
ffmpeg no longer prints everything into the terminal unless we're in `--verbose` mode. percentage progress text stays on one line while not in verbose mode.
* Added hint to run `avp --verbose` if `avp --log` is run with no avp_debug.log file present
* Classic Visualizer: add invert option
* Image component: fix path commandline option
* Image component: restrict file formats in CLI to match GUI
* Color component: add tooltip to color2 picker (second color of gradients)
* change tests to work with pytest-xdist
avp core stores its config (location of `settings.ini`) in temp directories if using multiple workers to run tests, so they don't interfere with each other. when using a single worker, the `tests/data/config` directory is still used
* check alt comp names when parsing cmdline
* rename `original.py` to `classic.py`
* move `component.py` into subpackage
* rename comp_original to comp_classic
* show traceback if renderFrame() raises exception
* do not try to insert non-existent components from project files
* add "composite" property for components
if a component returns "composite" then it will receive a frame to draw on during calls to previewRender and frameRender
* more tests of projects, actions, waveform, spectrum, image, color, classic
* do not change presetDir to "projects" within PresetManager
Diffstat (limited to 'src/avp/toolkit/ffmpeg.py')
| -rw-r--r-- | src/avp/toolkit/ffmpeg.py | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/src/avp/toolkit/ffmpeg.py b/src/avp/toolkit/ffmpeg.py index 5aedff3..93aa725 100644 --- a/src/avp/toolkit/ffmpeg.py +++ b/src/avp/toolkit/ffmpeg.py @@ -11,7 +11,7 @@ import signal from queue import PriorityQueue import logging -from .. import core +from ..core import Core from .common import checkOutput, pipeWrapper @@ -19,7 +19,7 @@ log = logging.getLogger("AVP.Toolkit.Ffmpeg") class FfmpegVideo: - """Opens a pipe to ffmpeg and stores a buffer of raw video frames.""" + """Opens an input pipe to ffmpeg and stores a buffer of raw video frames.""" # error from the thread used to fill the buffer threadError = None @@ -53,7 +53,7 @@ class FfmpegVideo: kwargs["filter_"] = None self.command = [ - core.Core.FFMPEG_BIN, + Core.FFMPEG_BIN, "-thread_queue_size", "512", "-r", @@ -98,11 +98,11 @@ class FfmpegVideo: self.frameBuffer.task_done() def fillBuffer(self): - from ..component import ComponentError + from ..libcomponent import ComponentError - if core.Core.logEnabled: + if Core.logEnabled: logFilename = os.path.join( - core.Core.logDir, "render_%s.log" % str(self.component.compPos) + Core.logDir, "render_%s.log" % str(self.component.compPos) ) log.debug("Creating ffmpeg process (log at %s)", logFilename) with open(logFilename, "w") as logf: @@ -176,7 +176,7 @@ def findFfmpeg(): if getattr(sys, "frozen", False): # The application is frozen - bin = os.path.join(core.Core.wd, bin) + bin = os.path.join(Core.wd, bin) with open(os.devnull, "w") as f: try: @@ -187,7 +187,9 @@ def findFfmpeg(): return bin -def createFfmpegCommand(inputFile, outputFile, components, duration=-1): +def createFfmpegCommand( + inputFile, outputFile, components, duration=-1, logLevel="info" +): """ Constructs the major ffmpeg command used to export the video """ @@ -195,7 +197,6 @@ def createFfmpegCommand(inputFile, outputFile, components, duration=-1): duration = getAudioDuration(inputFile) safeDuration = "{0:.3f}".format(duration - 0.05) # used by filters duration = "{0:.3f}".format(duration + 0.1) # used by input sources - Core = core.Core # Test if user has libfdk_aac encoders = checkOutput("%s -encoders -hide_banner" % Core.FFMPEG_BIN, shell=True) @@ -243,6 +244,8 @@ def createFfmpegCommand(inputFile, outputFile, components, duration=-1): ffmpegCommand = [ Core.FFMPEG_BIN, + "-loglevel", + logLevel, "-thread_queue_size", "512", "-y", # overwrite the output file if it already exists. @@ -415,7 +418,7 @@ def createAudioFilterCommand(extraAudio, duration): def testAudioStream(filename): """Test if an audio stream definitely exists""" audioTestCommand = [ - core.Core.FFMPEG_BIN, + Core.FFMPEG_BIN, "-i", filename, "-vn", @@ -433,7 +436,7 @@ def testAudioStream(filename): def getAudioDuration(filename): """Try to get duration of audio file as float, or False if not possible""" - command = [core.Core.FFMPEG_BIN, "-i", filename] + command = [Core.FFMPEG_BIN, "-i", filename] try: fileInfo = checkOutput(command, stderr=subprocess.STDOUT) @@ -473,7 +476,7 @@ def readAudioFile(filename, videoWorker): return command = [ - core.Core.FFMPEG_BIN, + Core.FFMPEG_BIN, "-i", filename, "-f", @@ -498,7 +501,7 @@ def readAudioFile(filename, videoWorker): progress = 0 lastPercent = None while True: - if core.Core.canceled: + if Core.canceled: return # read 2 seconds of audio progress += 4 @@ -543,3 +546,18 @@ def exampleSound(style="white", extra="apulsator=offset_l=0.35:offset_r=0.67"): src = "0.1*sin(2*PI*(360-2.5/2)*t) | 0.1*sin(2*PI*(360+2.5/2)*t)" return "aevalsrc='%s', %s%s" % (src, extra, ", " if extra else "") + + +def checkFfmpegVersion(): + try: + with open(os.devnull, "w") as f: + ffmpegVers = checkOutput([Core.FFMPEG_BIN, "-version"], stderr=f) + ffmpegVers = str(ffmpegVers).split()[2].split(".", 1)[0] + if ffmpegVers.startswith("n"): + ffmpegVers = ffmpegVers[1:] + versionNum = int(ffmpegVers) + goodVersion = versionNum > 3 + except Exception: + versionNum = -1 + goodVersion = False + return goodVersion, versionNum |
