| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- #!/usr/bin/env python
- import argparse
- import errno
- from math import floor
- import ffmpeg
- import sys
- WAVES_BACKGROUND_IMAGE_RATIO = 0.2
- WAVES_IMAGE_RATIO = 0.15
- def main():
- parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=True)
- parser.add_argument("--audio",
- help="input audio filename", required=True)
- parser.add_argument("--background",
- help="visualization background filename", required=True)
- parser.add_argument("--output",
- help="output video filename", required=True)
- parser.add_argument("--vis-color", nargs='*',
- help="colors for visualization waveforms", required=False, default=["0xffffff"])
- parser.add_argument("--background-color",
- help="backgroundcolor for visualization waveforms", required=False, default="0x000000")
- args, _ = parser.parse_known_args()
- duration = get_audio_duration(args.audio)
- (bg_height, bg_width) = get_image_resolution(args.background)
- waves_height = floor(bg_height * WAVES_IMAGE_RATIO)
- waves_background_height = floor(bg_height * WAVES_IMAGE_RATIO)
- # Compile the waves and a background color
- stream = ffmpeg.input(args.audio)
- vis_colors = "|".join(args.vis_color)
- vid_stream = (
- stream
- .filter("showwaves", s="%dx%d" % (bg_width, waves_height), mode="cline", colors=vis_colors)
- .filter("format", "rgba")
- .filter("colorchannelmixer", aa=0.9)
- )
- background_stream = (
- ffmpeg.input("color=c=%s:s=%dx%d:d=%ss" % (args.background_color, bg_width, waves_background_height, duration), f="lavfi")
- .filter("format", "rgba")
- .filter("colorchannelmixer", aa=0.5)
- )
- waves_center_offset = floor((waves_background_height - waves_height)/2)
- viz = ffmpeg.filter([background_stream, vid_stream], 'overlay', 0, waves_center_offset)
- waves_background_center_offset = floor((bg_height - waves_background_height)/2)
- # Overlay the waves stream on top of our static image
- vid_stream = ffmpeg.filter([ffmpeg.input(args.background), viz], 'overlay', 0, waves_background_center_offset)
- ffmpeg.output(stream.audio, vid_stream, args.output).run()
- # Get image resolution using ffprobe
- def get_image_resolution(image_filename):
- metadata = get_metadata(image_filename)
- height = metadata["streams"][0]["height"]
- width = metadata["streams"][0]["width"]
- return (height, width)
- # Get audio duration using ffprobe
- def get_audio_duration(audio_filename):
- metadata = get_metadata(audio_filename)
- return metadata["format"]["duration"]
- def get_metadata(filename):
- metadata = ffmpeg.probe(filename)
- return metadata
- if __name__ == "__main__":
- try:
- main()
- except KeyboardInterrupt:
- # The user asked the program to exit
- sys.exit(1)
- except IOError as e:
- # When this program is used in a shell pipeline and an earlier program in
- # the pipeline is terminated, we'll receive an EPIPE error. This is normal
- # and just an indication that we should exit after processing whatever
- # input we've received -- we don't consume standard input so we can just
- # exit cleanly in that case.
- if e.errno != errno.EPIPE:
- raise
- # We still exit with a non-zero exit code though in order to propagate the
- # error code of the earlier process that was terminated.
- sys.exit(1)
- sys.exit(0)
|