@@ -181,12 +181,18 @@ def video_stream_color_space(stream) -> str | None:
181181 return VIDEO_TRANSFER_COLOR_SPACES .get (stream .color_trc )
182182
183183
184- def video_encoder_options (codec : VideoCodec , crf : float | None ) -> dict [str , str ]:
185- if crf is None :
186- return {}
187- if codec == VideoCodec .AV1 and crf == 0 :
188- return {"svtav1-params" : "lossless=1" }
189- return {"crf" : str (crf )}
184+ def video_encoder_options (
185+ codec : VideoCodec , crf : float | None , preset : str | None = None
186+ ) -> dict [str , str ]:
187+ options = {}
188+ if preset is not None and codec == VideoCodec .H264 :
189+ options ["preset" ] = preset
190+ if crf is not None :
191+ if codec == VideoCodec .AV1 and crf == 0 :
192+ options ["svtav1-params" ] = "lossless=1"
193+ else :
194+ options ["crf" ] = str (crf )
195+ return options
190196
191197
192198def webm_streams_compatible (streams ) -> bool :
@@ -594,6 +600,7 @@ def save_to(
594600 bit_depth : int | None = None ,
595601 crf : float | None = None ,
596602 color_space : str | None = None ,
603+ preset : str | None = None ,
597604 ):
598605 if color_space is not None and color_space not in VIDEO_COLOR_TRANSFERS :
599606 raise ValueError (f"Unsupported video color space: { color_space } " )
@@ -632,7 +639,7 @@ def save_to(
632639 if not reuse_streams :
633640 if bit_depth is None :
634641 bit_depth = source_bit_depth
635- return self ._save_transcoded (container , path , format = format , codec = codec , metadata = metadata , bit_depth = bit_depth , crf = crf , color_space = color_space )
642+ return self ._save_transcoded (container , path , format = format , codec = codec , metadata = metadata , bit_depth = bit_depth , crf = crf , color_space = color_space , preset = preset )
636643
637644 streams = container .streams
638645
@@ -667,6 +674,7 @@ def _save_transcoded(
667674 bit_depth : int ,
668675 crf : float | None = None ,
669676 color_space : str | None = None ,
677+ preset : str | None = None ,
670678 ):
671679 """Re-encode one frame at a time; peak memory does not scale with video length."""
672680 open_kwargs , output_format , output_codec = video_output_config (path , format , codec )
@@ -844,7 +852,7 @@ def drain_audio(final=False):
844852 out_video .width = out_width
845853 out_video .height = out_height
846854 out_video .pix_fmt = pix_fmt
847- out_video .options = video_encoder_options (output_codec , crf )
855+ out_video .options = video_encoder_options (output_codec , crf , preset )
848856 if preserve_source_color :
849857 copy_color_properties (video_stream , out_video .codec_context )
850858 elif color_space is not None :
@@ -1074,6 +1082,7 @@ def save_to(
10741082 bit_depth : int | None = None ,
10751083 crf : float | None = None ,
10761084 color_space : str | None = None ,
1085+ preset : str | None = None ,
10771086 ):
10781087 """Save the video to a file path or BytesIO buffer."""
10791088 if color_space is None :
@@ -1100,7 +1109,7 @@ def save_to(
11001109 video_stream .width = self .__components .images .shape [2 ]
11011110 video_stream .height = self .__components .images .shape [1 ]
11021111 video_stream .pix_fmt = pix_fmt
1103- video_stream .options = video_encoder_options (output_codec , crf )
1112+ video_stream .options = video_encoder_options (output_codec , crf , preset )
11041113 if color_space is not None :
11051114 set_video_color_properties (video_stream .codec_context , color_space )
11061115
0 commit comments