4040 from manim .renderer .opengl_renderer import OpenGLRenderer
4141
4242
43+ def to_av_frame_rate (fps ):
44+ epsilon1 = 1e-4
45+ epsilon2 = 0.02
46+
47+ if isinstance (fps , int ):
48+ (num , denom ) = (fps , 1 )
49+ elif abs (fps - round (fps )) < epsilon1 :
50+ (num , denom ) = (round (fps ), 1 )
51+ else :
52+ denom = 1001
53+ num = round (fps * denom / 1000 ) * 1000
54+ if abs (fps - num / denom ) >= epsilon2 :
55+ raise ValueError ("invalid frame rate" )
56+
57+ return av .utils .Fraction (num , denom )
58+
59+
4360class SceneFileWriter :
4461 """
4562 SceneFileWriter is the object that actually writes the animations
@@ -506,9 +523,7 @@ def open_partial_movie_stream(self, file_path=None) -> None:
506523 file_path = self .partial_movie_files [self .renderer .num_plays ]
507524 self .partial_movie_file_path = file_path
508525
509- fps = config ["frame_rate" ]
510- if fps == int (fps ): # fps is integer
511- fps = int (fps )
526+ fps = to_av_frame_rate (config .frame_rate )
512527
513528 partial_movie_file_codec = "libx264"
514529 partial_movie_file_pix_fmt = "yuv420p"
@@ -530,7 +545,7 @@ def open_partial_movie_stream(self, file_path=None) -> None:
530545 with av .open (file_path , mode = "w" ) as video_container :
531546 stream = video_container .add_stream (
532547 partial_movie_file_codec ,
533- rate = config . frame_rate ,
548+ rate = fps ,
534549 options = av_options ,
535550 )
536551 stream .pix_fmt = partial_movie_file_pix_fmt
@@ -636,7 +651,7 @@ def combine_files(
636651 output_stream .pix_fmt = "pal8"
637652 output_stream .width = config .pixel_width
638653 output_stream .height = config .pixel_height
639- output_stream .rate = config .frame_rate
654+ output_stream .rate = to_av_frame_rate ( config .frame_rate )
640655 graph = av .filter .Graph ()
641656 input_buffer = graph .add_buffer (template = partial_movies_stream )
642657 split = graph .add ("split" )
@@ -663,7 +678,8 @@ def combine_files(
663678 while True :
664679 try :
665680 frame = graph .pull ()
666- frame .time_base = output_stream .codec_context .time_base
681+ if output_stream .codec_context .time_base is not None :
682+ frame .time_base = output_stream .codec_context .time_base
667683 frame .pts = frames_written
668684 frames_written += 1
669685 output_container .mux (output_stream .encode (frame ))
0 commit comments