I feel this question straddles the line between the Generic Computer Advice Thread and this one. It's about a Python 3 script. It automates the tedious process of interpreting raw video data as audio to be encoded (step 1), decoding it back to a raw format (step 2), then putting it into a lossless video codec for later use (step 3). It's an odd thing to do, but it produces interesting results, I think. Without it, those are 3 long and error-prone commands in FFmpeg.
I want to ask about how to implement error checking in the arguments. Here are the instructions:
Usage: vid-autoencode [resolution] [framerate] [pixel format] [filename w/ extension] [audio codec] [bitrate]
I want it to expect the following things and warn (raise an exception(?) and ask Y/N to continue) if it's out of range:
[resolution] : string in format n + "x" + m. n, m are unsigned integers. Example: 1920x1080.
[framerate] : positive integer (yes, this completely ignores edge cases like NTSC framerate (29.97... FPS), but I'm not working with those things yet.)
[pixel_format] : matches a list of possible pixel formats (there are too many to count; I will not list them here)
[filename w/ extension]: has ".raw" at the end.
[audio codec]: matches a list of possible audio codecs (again, too many to count)
[bitrate]: either unsigned integer, or in the form n + "k", n being an unsigned integer. Examples: 128k, 48000.
What's the best way to do these checks?
import subprocess
import sys
import os
## This script assumes you have FFmpeg installed in PATH. If editing directly, you MUST encase all parameters in quotes, including the numbers.
## No error-correction done on variables; the whole script expects string type.
## You will need at least 2.5 times the size of the original video file free on disk. Be warned!
## Only accepts raw video files.
## Prints usage information if given no parameters.
print(sys.argv)
if len(sys.argv) == 1:
print("Usage: vid-autoencode [resolution] [framerate] [pixel format] [filename w/ extension] [audio codec] [bitrate]\n")
sys.exit()
## Variables
#### Step 1
in_filename = os.path.splitext(sys.argv[4])[0]
in_extension = os.path.splitext(sys.argv[4])[1]
step1_format = "u8"
step1_out_extension = ".mkv"
## While tempting, it is inadvisable to set sample_rate any higher than 48000.
## Opus only supports sampling rates of up to 48 KHz, for instance.
sample_rate = "48000"
audio_codec = sys.argv[5]
bitrate_codec = sys.argv[6]
#### Step 2
# (no new variables; all recycled from Step 1)
#### Step 3.
## File-specific parameters. Set these equal to the original video's settings.
resolution = sys.argv[1]
framerate = sys.argv[2]
pixel_format = sys.argv[3]
## Final video encoder.
out_vid_codec = "ffvhuff"
## Combined filenames. Used for brevity.
in_file = str(in_filename + in_extension)
step1_out = in_filename + "-" + audio_codec + "-" + bitrate_codec
step2_out = in_filename + "-conv-" + audio_codec + "-" + bitrate_codec
step3_out = in_filename + "-" + out_vid_codec + "-" + audio_codec + "-" + bitrate_codec
## Step 1: Interpret raw RGB 24-bit video as if it were signed 8-bit PCM. Converts to an audio codec.
## 8-bit PCM is mandatory; you WILL get psychedelic artifacts with any other format and a lossy codec.
## Or maybe you want that. The variable to change is "step1_format", but I will not be responsible for any seizures that may occur.
step1_list = ["ffmpeg","-y","-f", step1_format,"-ar",sample_rate,"-i",in_file,"-c:a",audio_codec,"-b:a",str(bitrate_codec),step1_out + step1_out_extension]
print(step1_list)
subprocess.run(step1_list)
## Step 2: Decode the encoded "audio" back into raw 8-bit PCM.
step2_list = ["ffmpeg","-y","-i",step1_out+step1_out_extension,"-f",step1_format,"-ar",sample_rate,step2_out + in_extension]
print(step2_list)
subprocess.run(step2_list)
## Step 3: Push our new raw video into video, encoding to a video codec of your choice.
## For best results, use a lossless codec. ffvhuff is used here, and you may need to modify the command to use different codecs like x264 and x265.
## That is left as an exercise for the reader.
step3_list = ["ffmpeg","-y","-f","rawvideo","-s",resolution,"-r",framerate,"-pix_fmt",pixel_format,"-i",step2_out + in_extension,"-c:v",out_vid_codec,step3_out + step1_out_extension]
print(step3_list)
subprocess.run(step3_list)