I am transcoding video to different quality using ffmpeg using subprocess in Python. I want to make my transcoding faster. I tried multi-threading but it didn't help. Hardware acceleration is not possible as we are using an AWS EC2 t3.large instance at this time, which has 2 CPUs, 8GiB memory, and 30% baseline performance. Can you suggest something maybe regarding the ffmpeg command or update the code?
def transcode_video(video, quality, file_name):
try:
quality_mapping = {
"360p": "640x360",
"480p": "854x480",
"720p": "1280x720",
"1080p": "1920x1080"
}
if quality not in quality_mapping:
raise ValueError(f"Quality '{quality}' not supported")
video_name, video_ext = os.path.splitext(file_name)
# Construct output path with quality suffix
output_path = f"{video_name}_{quality}{video_ext}"
# Create FFmpeg object with streaming
ffmpeg_command = [
'ffmpeg',
'-i', 'pipe:0',
'-vf', f'scale={quality_mapping[quality]}',
'-c:a', 'aac',
'-c:v', 'libx264',
'-preset', 'ultrafast',
'-crf', '23',
'-strict', 'experimental',
output_path
]
# Use subprocess.PIPE for stdin and stdout
with subprocess.Popen(ffmpeg_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
# Write video content to stdin
process.stdin.write(video.read())
process.stdin.close() # Close stdin to indicate the end of input
# Wait for the process to finish
process.wait()
return output_path
except FileNotFoundError as e:
# Clean up temporary file
# if 'temp_file_path' in locals() and os.path.exists(temp_file_path):
# os.remove(temp_file_path)
# Remove output file after returning
if 'output_path' in locals() and os.path.exists(output_path):
os.remove(output_path)
raise e
except subprocess.CalledProcessError as e:
if 'output_path' in locals() and os.path.exists(output_path):
os.remove(output_path)
raise e
except Exception as e:
if 'output_path' in locals() and os.path.exists(output_path):
os.remove(output_path)
raise e
-
1\$\begingroup\$ Encoding video is slow. You can make it faster by picking a cheaper codec or cheaper settings for your current codec. But that invariably leads to larger files (ie less compression) because speed and amount of compression tend to be inversely related. \$\endgroup\$Cris Luengo– Cris Luengo2024年03月28日 13:47:39 +00:00Commented Mar 28, 2024 at 13:47
1 Answer 1
Prefer to pass around modern Path
over str
.
Prefer the modern except (FileNotFoundError, CalledProcessError) as e:
syntax.
Prefer the modern .check_call()
interface.
Do we need to probe locals()
?
A multiprocessing pool
can burn two cores.
I understand that video
is an open file handle, and this function conforms to an API. But rather than schlepping all the bits through the cpython interpreter, it might be slightly faster to pass the child process a pathname and let ffmpeg worry about the reading.
-
\$\begingroup\$ thank you for this, it improved a lot in local environment but it didn't help my ec2 environment. \$\endgroup\$Rai Shahnawaz– Rai Shahnawaz2024年07月02日 17:14:02 +00:00Commented Jul 2, 2024 at 17:14