video2x/bin/ffmpeg.py

156 lines
4.6 KiB
Python
Raw Normal View History

2018-12-11 20:52:48 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: FFMPEG Class
Author: K4YT3X
Date Created: Feb 24, 2018
2019-03-19 17:07:20 +00:00
Last Modified: March 19, 2019
2018-12-11 20:52:48 +00:00
Description: This class handles all FFMPEG related
operations.
"""
from avalon_framework import Avalon
import json
2018-12-11 20:52:48 +00:00
import subprocess
class Ffmpeg:
"""This class communicates with ffmpeg
This class deals with ffmpeg. It handles extracitng
frames, stripping audio, converting images into videos
and inserting audio tracks to videos.
"""
def __init__(self, ffmpeg_settings):
self.ffmpeg_settings = ffmpeg_settings
self._parse_settings()
def _parse_settings(self):
""" Parse ffmpeg settings
"""
self.ffmpeg_path = self.ffmpeg_settings['ffmpeg_path']
2019-03-19 17:07:20 +00:00
# add a forward slash to directory if not present
# otherwise there will be a format error
if self.ffmpeg_path[-1] != '/' and self.ffmpeg_path[-1] != '\\':
2019-03-19 17:07:20 +00:00
self.ffmpeg_path = '{}\\'.format(self.ffmpeg_path)
2019-03-19 17:07:20 +00:00
self.ffmpeg_binary = '{}ffmpeg.exe'.format(self.ffmpeg_path)
self.ffmpeg_hwaccel = self.ffmpeg_settings['ffmpeg_hwaccel']
self.extra_arguments = self.ffmpeg_settings['extra_arguments']
2018-12-11 20:52:48 +00:00
def get_video_info(self, input_video):
""" Gets input video information
2018-12-11 20:52:48 +00:00
This method reads input video information
using ffprobe in dictionary.
2018-12-11 20:52:48 +00:00
Arguments:
input_video {string} -- input video file path
Returns:
dictionary -- JSON text of input video information
2018-12-11 20:52:48 +00:00
"""
2019-03-19 17:07:20 +00:00
execute = [
'{}ffprobe.exe'.format(self.ffmpeg_path),
'-v',
'quiet',
'-print_format',
'json',
'-show_format',
'-show_streams',
'-i',
'{}'.format(input_video)
]
Avalon.debug_info('Executing: {}'.format(' '.join(execute)))
json_str = subprocess.run(execute, check=True, stdout=subprocess.PIPE).stdout
return json.loads(json_str.decode('utf-8'))
2018-12-11 20:52:48 +00:00
def extract_frames(self, input_video, extracted_frames):
"""Extract every frame from original videos
2018-12-11 20:52:48 +00:00
This method extracts every frame from videoin
using ffmpeg
2018-12-11 20:52:48 +00:00
Arguments:
input_video {string} -- input video path
extracted_frames {string} -- video output folder
2018-12-11 20:52:48 +00:00
"""
2019-03-19 17:07:20 +00:00
execute = [
self.ffmpeg_binary,
'-i',
'{}'.format(input_video),
'{}\\extracted_%0d.png'.format(extracted_frames),
'-y'
]
execute += self.extra_arguments
Avalon.debug_info('Executing: {}'.format(' '.join(execute)))
subprocess.run(execute, shell=True, check=True)
2018-12-11 20:52:48 +00:00
def convert_video(self, framerate, resolution, upscaled_frames):
2018-12-11 20:52:48 +00:00
"""Converts images into videos
This method converts a set of images into a
video.
Arguments:
framerate {float} -- target video framerate
resolution {string} -- target video resolution
upscaled_frames {string} -- source images folder
2018-12-11 20:52:48 +00:00
"""
2019-03-19 17:07:20 +00:00
execute = [
self.ffmpeg_binary,
'-r',
str(framerate),
'-f',
'image2',
'-s',
resolution,
'-i',
'{}\\extracted_%d.png'.format(upscaled_frames),
'-vcodec',
'libx264',
'-crf',
'25',
'-pix_fmt',
'yuv420p',
'{}\\no_audio.mp4'.format(upscaled_frames),
'-y'
]
execute += self.extra_arguments
Avalon.debug_info('Executing: {}'.format(' '.join(execute)))
subprocess.run(execute, shell=True, check=True)
2018-12-11 20:52:48 +00:00
def migrate_audio_tracks_subtitles(self, input_video, output_video, upscaled_frames):
""" Migrates audio tracks and subtitles from input video to output video
2018-12-11 20:52:48 +00:00
Arguments:
input_video {string} -- input video file path
output_video {string} -- output video file path
upscaled_frames {string} -- directory containing upscaled frames
2018-12-11 20:52:48 +00:00
"""
2019-03-19 17:07:20 +00:00
execute = [
self.ffmpeg_binary,
'-i',
'{}\\no_audio.mp4'.format(upscaled_frames),
'-i',
'{}'.format(input_video),
'-map',
'0:v:0?',
'-map',
'1?',
'-c',
'copy',
'-map',
'-1:v?',
'{}'.format(output_video),
'-y'
]
execute += self.extra_arguments
Avalon.debug_info('Executing: {}'.format(' '.join(execute)))
subprocess.run(execute, shell=True, check=True)