Skip to content

Instantly share code, notes, and snippets.

@ZachAR3
Created July 13, 2023 18:33
Show Gist options
  • Save ZachAR3/d119e69f219b5a052bfdf7d1766725e5 to your computer and use it in GitHub Desktop.
Save ZachAR3/d119e69f219b5a052bfdf7d1766725e5 to your computer and use it in GitHub Desktop.
FFMPEG Encoder
# Example code from https://github.com/OpenShot/openshot-qt/blob/develop/src/windows/export.py
# Create FFmpegWriter
try:
w = openshot.FFmpegWriter(export_file_path)
# Set video options
if export_type in [_("Video & Audio"), _("Video Only"), _("Image Sequence")]:
w.SetVideoOptions(True,
video_settings.get("vcodec"),
openshot.Fraction(video_settings.get("fps").get("num"),
video_settings.get("fps").get("den")),
video_settings.get("width"),
video_settings.get("height"),
openshot.Fraction(video_settings.get("pixel_ratio").get("num"),
video_settings.get("pixel_ratio").get("den")),
video_settings.get("interlace"),
video_settings.get("topfirst"),
video_settings.get("video_bitrate"))
# Set audio options
if export_type in [_("Video & Audio"), _("Audio Only")]:
w.SetAudioOptions(True,
audio_settings.get("acodec"),
audio_settings.get("sample_rate"),
audio_settings.get("channels"),
audio_settings.get("channel_layout"),
audio_settings.get("audio_bitrate"))
# Prepare the streams
w.PrepareStreams()
# These extra options should be set in an extra method
# No feedback is given to the user
# TODO: Tell user if option is not available
if export_type in [_("Audio Only")]:
# Muxing options for mp4/mov
w.SetOption(openshot.AUDIO_STREAM, "muxing_preset", "mp4_faststart")
else:
# Muxing options for mp4/mov
w.SetOption(openshot.VIDEO_STREAM, "muxing_preset", "mp4_faststart")
# Set the quality in case crf, cqp or qp was selected
if "crf" in self.txtVideoBitRate.text():
w.SetOption(openshot.VIDEO_STREAM, "crf", str(int(video_settings.get("video_bitrate"))) )
elif "cqp" in self.txtVideoBitRate.text():
w.SetOption(openshot.VIDEO_STREAM, "cqp", str(int(video_settings.get("video_bitrate"))) )
elif "qp" in self.txtVideoBitRate.text():
w.SetOption(openshot.VIDEO_STREAM, "qp", str(int(video_settings.get("video_bitrate"))) )
# Open the writer
w.Open()
# Notify window of export started
title_message = ""
self.ExportStarted.emit(export_file_path, video_settings.get("start_frame"), video_settings.get("end_frame"))
progressstep = max(1 , round(( video_settings.get("end_frame") - video_settings.get("start_frame") ) / 1000))
start_time_export = time.time()
start_frame_export = video_settings.get("start_frame")
end_frame_export = video_settings.get("end_frame")
last_exported_time = time.time()
last_displayed_exported_portion = 0.0
# Write each frame in the selected range
for frame in range(video_settings.get("start_frame"), video_settings.get("end_frame") + 1):
# Update progress bar (emit signal to main window)
end_time_export = time.time()
if ((frame % progressstep) == 0) or ((end_time_export - last_exported_time) > 1):
current_exported_portion = (frame - start_frame_export) * 1.0 / (end_frame_export - start_frame_export)
if ((current_exported_portion - last_displayed_exported_portion) > 0.0):
# the log10 of the difference of the fraction of the completed frames is the negativ
# number of digits after the decimal point after which the first digit is not 0
digits_after_decimalpoint = math.ceil( -2.0 - math.log10( current_exported_portion - last_displayed_exported_portion ))
else:
digits_after_decimalpoint = 1
if digits_after_decimalpoint < 1:
# We want at least 1 digit after the decimal point
digits_after_decimalpoint = 1
if digits_after_decimalpoint > 5:
# We don't want not more than 5 digits after the decimal point
digits_after_decimalpoint = 5
last_displayed_exported_portion = current_exported_portion
format_of_progress_string = "%4." + str(digits_after_decimalpoint) + "f%% "
last_exported_time = time.time()
if ((frame - start_frame_export) != 0) & ((end_time_export - start_time_export) != 0):
seconds_left = round(( start_time_export - end_time_export )*( frame - end_frame_export )/( frame - start_frame_export ))
fps_encode = ((frame - start_frame_export)/(end_time_export-start_time_export))
if frame == end_frame_export:
title_message = _("Finalizing video export, please wait...")
else:
title_message = titlestring(seconds_left, fps_encode, "Remaining")
# Emit frame exported
self.ExportFrame.emit(
title_message,
video_settings.get("start_frame"),
video_settings.get("end_frame"),
frame,
format_of_progress_string
)
# Process events (to show the progress bar moving)
QCoreApplication.processEvents()
# track largest frame processed
max_frame = frame
# Write the frame object to the video
w.WriteFrame(self.timeline.GetFrame(frame))
# Check if we need to bail out
if not self.exporting:
break
# Close writer
w.Close()
# Emit final exported frame (with elapsed time)
seconds_run = round((end_time_export - start_time_export))
title_message = titlestring(seconds_run, fps_encode, "Elapsed")
self.ExportFrame.emit(
title_message,
video_settings.get("start_frame"),
video_settings.get("end_frame"),
max_frame,
format_of_progress_string
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment