Skip to content

Commit

Permalink
Progress bars and messages now with Proglog
Browse files Browse the repository at this point in the history
  • Loading branch information
Zulko committed Dec 16, 2018
1 parent dbc9ab1 commit bfad5ea
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 152 deletions.
2 changes: 1 addition & 1 deletion docs/examples/quick_recipes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Getting the average frame of a video
clip = VideoFileClip("video.mp4")
fps= 1.0 # take one frame per second
nframes = clip.duration*fps # total number of frames used
total_image = sum(clip.iter_frames(fps,dtype=float,progress_bar=True))
total_image = sum(clip.iter_frames(fps,dtype=float,logger='bar'))
average_image = ImageClip(total_image/ nframes)
average_image.save_frame("average_test.png")

28 changes: 11 additions & 17 deletions moviepy/Clip.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
convert_to_seconds,
use_clip_fps_by_default)
from tqdm import tqdm
import proglog


class Clip:
Expand Down Expand Up @@ -443,7 +444,7 @@ def cutout(self, ta, tb):

@requires_duration
@use_clip_fps_by_default
def iter_frames(self, fps=None, with_times = False, progress_bar=False,
def iter_frames(self, fps=None, with_times = False, logger=None,
dtype=None):
""" Iterates over all the frames of the clip.
Expand All @@ -469,22 +470,15 @@ def iter_frames(self, fps=None, with_times = False, progress_bar=False,
>>> print ( [frame[0,:,0].max()
for frame in myclip.iter_frames()])
"""

def generator():
for t in np.arange(0, self.duration, 1.0/fps):
frame = self.get_frame(t)
if (dtype is not None) and (frame.dtype != dtype):
frame = frame.astype(dtype)
if with_times:
yield t, frame
else:
yield frame

if progress_bar:
nframes = int(self.duration*fps)+1
return tqdm(generator(), total=nframes)

return generator()
logger = proglog.default_bar_logger(logger)
for t in logger.iter_bar(t=np.arange(0, self.duration, 1.0/fps)):
frame = self.get_frame(t)
if (dtype is not None) and (frame.dtype != dtype):
frame = frame.astype(dtype)
if with_times:
yield t, frame
else:
yield frame

def close(self):
"""
Expand Down
36 changes: 16 additions & 20 deletions moviepy/audio/AudioClip.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import numpy as np
import proglog
from moviepy.audio.io.ffmpeg_audiowriter import ffmpeg_audiowrite
from moviepy.decorators import requires_duration
from moviepy.tools import deprecated_version_of, extensions_dict
Expand Down Expand Up @@ -61,11 +62,12 @@ def __init__(self, make_frame=None, duration=None, fps=None):

@requires_duration
def iter_chunks(self, chunksize=None, chunk_duration=None, fps=None,
quantize=False, nbytes=2, progress_bar=False):
quantize=False, nbytes=2, logger=None):
""" Iterator that returns the whole sound array of the clip by chunks
"""
if fps is None:
fps = self.fps
logger = proglog.default_bar_logger(logger)
if chunk_duration is not None:
chunksize = int(chunk_duration*fps)

Expand All @@ -74,19 +76,13 @@ def iter_chunks(self, chunksize=None, chunk_duration=None, fps=None,
nchunks = totalsize // chunksize + 1

pospos = np.linspace(0, totalsize, nchunks + 1, endpoint=True, dtype=int)

def generator():
for i in range(nchunks):
size = pospos[i+1] - pospos[i]
assert(size <= chunksize)
tt = (1.0/fps)*np.arange(pospos[i], pospos[i+1])
yield self.to_soundarray(tt, nbytes=nbytes, quantize=quantize,
fps=fps, buffersize=chunksize)

if progress_bar:
return tqdm(generator(), total=nchunks)
else:
return generator()

for i in logger.iter_bar(chunk=list(range(nchunks))):
size = pospos[i+1] - pospos[i]
assert(size <= chunksize)
tt = (1.0/fps)*np.arange(pospos[i], pospos[i+1])
yield self.to_soundarray(tt, nbytes=nbytes, quantize=quantize,
fps=fps, buffersize=chunksize)

@requires_duration
def to_soundarray(self, tt=None, fps=None, quantize=False, nbytes=2, buffersize=50000):
Expand Down Expand Up @@ -136,19 +132,19 @@ def to_soundarray(self, tt=None, fps=None, quantize=False, nbytes=2, buffersize=

return snd_array

def max_volume(self, stereo=False, chunksize=50000, progress_bar=False):
def max_volume(self, stereo=False, chunksize=50000, logger=None):

stereo = stereo and (self.nchannels == 2)

maxi = np.array([0, 0]) if stereo else 0
for chunk in self.iter_chunks(chunksize=chunksize, progress_bar=progress_bar):
for chunk in self.iter_chunks(chunksize=chunksize,logger=logger):
maxi = np.maximum(maxi, abs(chunk).max(axis=0)) if stereo else max(maxi, abs(chunk).max())
return maxi

@requires_duration
def write_audiofile(self, filename, fps=None, nbytes=2, buffersize=2000,
codec=None, bitrate=None, ffmpeg_params=None,
write_logfile=False, verbose=True, progress_bar=True):
write_logfile=False, verbose=True, logger='bar'):
""" Writes an audio file from the AudioClip.
Expand Down Expand Up @@ -187,8 +183,8 @@ def write_audiofile(self, filename, fps=None, nbytes=2, buffersize=2000,
verbose
Boolean indicating whether to print infomation
progress_bar
Boolean indicating whether to show the progress bar.
logger
Either 'bar' or None or any Proglog logger
"""
if not fps:
Expand All @@ -210,7 +206,7 @@ def write_audiofile(self, filename, fps=None, nbytes=2, buffersize=2000,
codec=codec, bitrate=bitrate,
write_logfile=write_logfile, verbose=verbose,
ffmpeg_params=ffmpeg_params,
progress_bar=progress_bar)
logger=logger)


# The to_audiofile method is replaced by the more explicit write_audiofile.
Expand Down
35 changes: 9 additions & 26 deletions moviepy/audio/io/ffmpeg_audiowriter.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import subprocess as sp
import os
import proglog

from moviepy.compat import DEVNULL

import os

from moviepy.config import get_setting
from moviepy.decorators import requires_duration

from moviepy.tools import verbose_print


class FFMPEG_AudioWriter:
"""
Expand Down Expand Up @@ -146,19 +144,20 @@ def __exit__(self, exc_type, exc_value, traceback):
def ffmpeg_audiowrite(clip, filename, fps, nbytes, buffersize,
codec='libvorbis', bitrate=None,
write_logfile=False, verbose=True,
ffmpeg_params=None, progress_bar=True):
ffmpeg_params=None, logger='bar'):
"""
A function that wraps the FFMPEG_AudioWriter to write an AudioClip
to a file.
NOTE: verbose is deprecated.
"""

if write_logfile:
logfile = open(filename + ".log", 'w+')
else:
logfile = None

verbose_print(verbose, "[MoviePy] Writing audio in %s\n"%filename)

logger = proglog.default_bar_logger(logger)
logger(message="MoviePy - Writing audio in %s")
writer = FFMPEG_AudioWriter(filename, fps, nbytes, clip.nchannels,
codec=codec, bitrate=bitrate,
logfile=logfile,
Expand All @@ -167,27 +166,11 @@ def ffmpeg_audiowrite(clip, filename, fps, nbytes, buffersize,
for chunk in clip.iter_chunks(chunksize=buffersize,
quantize=True,
nbytes=nbytes, fps=fps,
progress_bar=progress_bar):
logger=logger):
writer.write_frames(chunk)

"""
totalsize = int(fps*clip.duration)
if (totalsize % buffersize == 0):
nchunks = totalsize // buffersize
else:
nchunks = totalsize // buffersize + 1
pospos = list(range(0, totalsize, buffersize))+[totalsize]
for i in tqdm(range(nchunks)):
tt = (1.0/fps)*np.arange(pospos[i],pospos[i+1])
sndarray = clip.to_soundarray(tt, nbytes= nbytes)
writer.write_frames(sndarray)
"""

writer.close()

if write_logfile:
logfile.close()

verbose_print(verbose, "[MoviePy] Done.\n")
logger(message="MoviePy - Done.")
17 changes: 11 additions & 6 deletions moviepy/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import sys
import warnings
import re
import proglog

import os
from .compat import DEVNULL
Expand All @@ -27,10 +28,13 @@ def verbose_print(verbose, s):
sys_write_flush(s)


def subprocess_call(cmd, verbose=True, errorprint=True):
""" Executes the given subprocess command."""

verbose_print(verbose, "\n[MoviePy] Running:\n>>> "+ " ".join(cmd))
def subprocess_call(cmd, logger='bar', errorprint=True):
""" Executes the given subprocess command.
Set logger to None or a custom Proglog logger to avoid printings.
"""
logger = proglog.default_bar_logger(logger)
logger(message='Moviepy - Running:\n>>> "+ " ".join(cmd)')

popen_params = {"stdout": DEVNULL,
"stderr": sp.PIPE,
Expand All @@ -45,10 +49,11 @@ def subprocess_call(cmd, verbose=True, errorprint=True):
proc.stderr.close()

if proc.returncode:
verbose_print(errorprint, "\n[MoviePy] This command returned an error !")
if errorprint:
logger(message='Moviepy - Command returned an error')
raise IOError(err.decode('utf8'))
else:
verbose_print(verbose, "\n... command successful.\n")
logger(message='Moviepy - Command successful')

del proc

Expand Down
Loading

1 comment on commit bfad5ea

@Zulko
Copy link
Owner Author

@Zulko Zulko commented on bfad5ea May 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now logger is either 'bar' or None (no progress bars) or any proglog logger. See the proglog documentation:

https://github.com/Edinburgh-Genome-Foundry/Proglog

Please sign in to comment.