
    hP                    `   S r SSKJr  SSKrSSKrSSKJrJr  SSKJ	r	  SSK
JrJr  SSKrSSKrSSKJrJr  SSKJrJrJr  SS	KJr  SS
KJr  SSKJrJr  SSKJr   " S S\\R@                  RB                  5      r" " S S\RF                  R:                  \R@                  RB                  5      r$g)z>File for rendering and recording of vector-based environments.    )annotationsN)CallableSequence)deepcopy)AnySupportsFloat)errorlogger)ActTypeObsTypeRenderFrame)DependencyNotInstalled)warn)	VectorEnvVectorWrapper)	ArrayTypec                     ^  \ rS rSrSr/ SQrSSS jjr\SS j5       r    SU 4S jjr	SSS.     SU 4S	 jjjr
S
 rU 4S jrSrU =r$ )HumanRendering   zEAdds support for Human-based Rendering for Vector-based environments.)	rgb_arrayrgb_array_listdepth_arraydepth_array_listNc                J   [         R                  " X5        [        R                  R                  R                  XS9  X l        Su  U l        U l        U l        SU l	        SU l
        U R                  R                  U R                  ;   d"   SU R                   SUR                   S35       eSU R                  R                  ;   d   S5       eS	U R                  S
   ;  aC  [        U R                  R                  5      U l        U R                  S
   R!                  S	5        gg)zConstructor for Human Rendering of Vector-based environments.

Args:
    env: The vector environment
    screen_size: The rendering screen size otherwise the environment sub-env render size is used
)screen_size)NNNNz&Expected env.render_mode to be one of z
 but got ''
render_fpszYThe base environment must specify 'render_fps' to be used with the HumanRendering wrapperhumanrender_modes)r   __init__gymutilsRecordConstructorArgsr   scaled_subenv_sizenum_rowsnum_colswindowclockenvrender_modeACCEPTED_RENDER_MODESmetadatar   append)selfr)   r   s      ]/home/james-whalen/.local/lib/python3.13/site-packages/gymnasium/wrappers/vector/rendering.pyr    HumanRendering.__init__    s
    	t)		''000O&@P=
 HH  D$>$>>	m3D4N4N3OzZ]ZiZiYjjkl	m> DHH---	gf	g- $--77$TXX%6%67DMMM.)009 8    c                    g)zAlways returns ``'human'``.r    r.   s    r/   r*   HumanRendering.render_mode:   s     r1   c                F   > [         TU ]  U5      nU R                  5         U$ )zHPerform a step in the base environment and render a frame to the screen.)superstep_render_frame)r.   actionsresult	__class__s      r/   r8   HumanRendering.step?   s$     g&r1   seedoptionsc               B   > [         TU ]  XS9nU R                  5         U$ )z<Reset the base environment and render a frame to the screen.r>   )r7   resetr9   )r.   r?   r@   r;   r<   s       r/   rB   HumanRendering.resetG   s&     D:r1   c                b    SSK nU R                  R                  c   eU R                  R                  R                  S5      (       a7  U R                  R                  5       n[        U[        5      (       d   eUS   nOU R                  R                  5       nUc   e[        U5      U R                  :X  d   e[        S U 5       5      (       d$   SU Vs/ s H  n[        U5      PM     sn 35       e[        R                  " U[        R                  S9n[        R                   " US	S
9nU R"                  c  UR$                  SS U l        U R&                  Gc  UR$                  SS nUS   U R"                  S   -  nUS   U R"                  S   -  nSu  pxXx-  U R                  :  a;  Xv-  n	X-  n
X:X  a
  US-   US-   pOX:  a  US-  nOUS-  nXx-  U R                  :  a  M;  [)        U R"                  S   XS   -  -  U R"                  S   XtS   -  -  5      nXS   -  U-  U R"                  S   :X  d  XtS   -  U-  U R"                  S   :X  d   eXpl        Xl        [/        US   U-  5      [/        US   U-  5      4U l        U R*                  U R,                  -  U R                  :  d   eU R&                  S   U R,                  -  U R"                  S   ::  d   eU R&                  S   U R*                  -  U R"                  S   ::  d   e SSKn[        R2                  " U R"                  S-   [        R                  S9n[        R4                  " [        R6                  " U R,                  5      [        R6                  " U R*                  5      5      u  nn[9        [;        U R                  5      UR=                  5       UR=                  5       5       H{  u  nnnUR?                  UU   U R&                  SSS2   5      nUU R&                  S   -  nUU R&                  S   -  nUUUUU R&                  S   -   2UUU R&                  S   -   24'   M}     U R@                  cT  URC                  5         URD                  RC                  5         URD                  RG                  U R"                  5      U l         U RH                  c  URJ                  RM                  5       U l$        URN                  RQ                  U5      nU R@                  RS                  US5        URT                  RW                  5         U RH                  RY                  U RZ                  S   5        URD                  R]                  5         g! [         a    [        S5      ef = fs  snf ! [         a  n[        S5      UeSnAff = f)zKFetch the last frame from the base environment and render it to the screen.r   NzEpygame is not installed, run `pip install gymnasium[classic-control]`_lastc              3  V   #    U  H  n[        U[        R                  5      v   M!     g 7fN)
isinstancenpndarray).0renders     r/   	<genexpr>/HumanRendering._render_frame.<locals>.<genexpr>e   s!      
9GvJvrzz**s   ')zCExpected `env.render()` to return a numpy array, actually returned dtype)r            )axesrS   rT   rS   rS   zCopencv (cv2) is not installed, run `pip install "gymnasium[other]"`)rT   )r   r   r   )/pygameImportErrorr   r)   r*   endswithrM   rI   listlennum_envsalltyperJ   arrayuint8	transposer   shaper$   minr%   r&   intcv2zerosmeshgridarangeziprangeflattenresizer'   initdisplayset_moder(   timeClock	surfarraymake_surfacebliteventpumptickr,   flip)r.   rW   subenv_rendersrM   subenv_sizewidth_ratioheight_ratior%   r&   	row_ratio	col_ratioscaling_factorre   emerged_rgb_arraycolsrowsicolrowscaled_renderxysurfs                           r/   r9   HumanRendering._render_frameR   sZ   	 xx##///88((11!XX__.Nnd3333+B/N!XX__.N)))>"dmm333 
9G
 
 
 	Pm{Q|m{ciRVW]R^m{Q|P}~	 
 .An<H #-33Aa8D""*(..q3K%a.4+;+;A+>>K&q>D,<,<Q,??L!%H%5$3	$2	))1Ax!|h*MHMH %5 !  #xa.'@A  #xa.'@AN
 q>)N:d>N>Nq>QQ^+n<@P@PQR@SSU U %M$MKN^34KN^34'D#
 ==4==0DMMAAA**1-=AQAQRSATTTT**1-=AQAQRSATTTT	 88D$4$4t$;288L[[4==!9299T]];ST
duT]]3T\\^T\\^TKAsCJJ~a'8$:Q:QRVTVRV:WXMd--a00Ad--a00A
  A//222A//2224 U ;;KKMNN! ..11$2B2BCDK::**,DJ,,-=>v&

l34A  	(W 	" R}b  	(U	s)   U5 VV 5V
V.V))V.c                   > U R                   b.  SSKnUR                  R                  5         UR                  5         [        TU ]  5         g)zClose the rendering window.Nr   )r'   rW   rn   quitr7   close)r.   rW   r<   s     r/   r   HumanRendering.close   s2    ;;"NN!KKMr1   )r(   r,   r&   r%   r$   r   r'   rH   )r)   r   r   ztuple[int, int] | None)returnstr)r:   r   r   z?tuple[ObsType, ArrayType, ArrayType, ArrayType, dict[str, Any]])r?   zint | list[int] | Noner@   dict[str, Any] | Noner   tuple[ObsType, dict[str, Any]])__name__
__module____qualname____firstlineno____doc__r+   r    propertyr*   r8   rB   r9   r   __static_attributes____classcell__r<   s   @r/   r   r      s}    O:4  	H (,)-		 %	 '		
 
(	 	dL r1   r   c            	         ^  \ rS rSrSrSSSSSSSSS	 4	                     SS
 jjrS rS rS rSSS.     SU 4S jjjr	    SS jr
SU 4S jjrU 4S jrSS jrS rS rSrU =r$ )RecordVideo   a  Adds support for video recording for Vector-based environments.

The class is the same as gymnasium.wrappers.rendering.RecordVideo, but
expects multiple frames when rendering the environment (one for each
environment of the VectorEnv). Frames are concatenated into one frame such
that its aspect ratio is as close as possible to the desired one.

Examples - Run 5 environments for 200 timesteps, and save the video every 5 episodes:
>>> import os
>>> import gymnasium as gym
>>> from gymnasium.wrappers.vector import RecordVideo
>>> envs = gym.make_vec("CartPole-v1", num_envs=5, render_mode="rgb_array")
>>> envs = RecordVideo(
...     envs,
...     video_folder="save_videos_5envs",
...     video_aspect_ratio=(1,1),
...     episode_trigger=lambda t: t % 5 == 0,
... )
>>> _ = envs.reset(seed=123)
>>> _ = envs.action_space.seed(123)
>>> for i in range(200):
...     actions = envs.action_space.sample()
...     _ = envs.step(actions)
>>> envs.close()
>>> len(os.listdir("save_videos_5envs"))
2
rV   FNr   zrl-videoTc                    g)NTr3   )episodes    r/   <lambda>RecordVideo.<lambda>   s    4r1   c           
     2   [         R                  " X5        [        R                  R                  R                  U UUUUUU
S9  UR
                  S;   a  [        SUR
                   S3S5      eUc  Uc  SSKJn  UnUR                  R                  S	S5      nUb  Xl        OE[        U S
UR                  < S35        [        R                  R                  R                  U l        U R                  [        R                  R                  R                   :X  a  ["        R                  " S5        SU l        XPl        X`l        Xl        Xl        X@l        X0l        SU l        SU l        [6        R8                  R;                  U5      U l        [6        R8                  R?                  U R<                  5      (       a$  ["        R                  " SU R<                   S35        [6        R@                  " U R<                  SS9  U	c  U R                  R                  SS5      n	Xl!        Xl"        SU l#        US:w  a  UO
[I        S5      U l%        SU l&        / U l'        / U l(        SU l)        SU l*         SSK+ng! [X         a  n[Z        R\                  " S5      UeSnAff = f)a   Wrapper records videos of environment rollouts.

Args:
    env: The environment that will be wrapped
    video_folder (str): The folder where the recordings will be stored
    video_aspect_ratio (tuple): the desired aspect ratio of the video concatenating all environments. For example, (1, 1) means an
        aspect ratio of 1:1, while (16, 9) means 16:9.
    record_first_only (bool): if True, only the first environment is recorded.
    episode_trigger: Function that accepts an integer and returns ``True`` iff a recording should be started at this episode
    step_trigger: Function that accepts an integer and returns ``True`` iff a recording should be started at this step
    video_length (int): The length of recorded episodes. If 0, entire episodes are recorded.
        Otherwise, snippets of the specified length are captured
    name_prefix (str): Will be prepended to the filename of the recordings
    fps (int): The frame per second in the video. Provides a custom video fps for environment, if ``None`` then
        the environment metadata ``render_fps`` key is used if it exists, otherwise a default value of 30 is used.
    disable_logger (bool): Whether to disable moviepy logger or not, default it is disabled
    gc_trigger: Function that accepts an integer and returns ``True`` iff garbage collection should be performed after this episode

Note:
    For vector environments that use same-step autoreset (see https://farama.org/Vector-Autoreset-Mode for more details)
    then the final frame of the episode will not be included in the video.
)video_folderepisode_triggerstep_triggervideo_lengthname_prefixdisable_logger>   Nansir   zRender mode is z), which is incompatible with RecordVideo.zXInitialize your environment with a render_mode that returns an image, such as rgb_array.Nr   )capped_cubic_video_scheduleautoreset_modez. metadata doesn't specify its autoreset mode (z&), therefore, defaulting to next step.zVector environment's autoreset mode is same-step (https://farama.org/Vector-Autoreset-Mode). Recorded episodes will not contain the last frame of the episode.FrF   zOverwriting existing videos at zh folder (try specifying a different `video_folder` for the `RecordVideo` wrapper if this is not desired)T)exist_okr      inf>MoviePy is not installed, run `pip install "gymnasium[other]"`)/r   r    r!   r"   r#   r*   
ValueErrorgymnasium.utils.save_videor   r,   getr   r   vectorAutoresetMode	NEXT_STEP	SAME_STEPr
   has_autoresetr   r   r   
gc_triggerrecord_first_onlyvideo_aspect_ratio
frame_cols
frame_rowsospathabspathr   isdirmakedirsframes_per_secr   _video_namefloatr   	recordingrecorded_framesrender_historystep_id
episode_idmoviepyrX   r	   r   )r.   r)   r   r   r   r   r   r   r   fpsr   r   r   r   r   r   s                   r/   r    RecordVideo.__init__   sW   H 	t)		''00%+%%#) 	1 	
 ??55!#//!22[\j 
 "|';N9O))*:DA%"0%EcllEUU{| #&**":":"D"DD#**":":"D"DDKK q #.(,$!2"4GGOOL977==**++KK1$2C2C1D Es t 	D%%5;--##L"5C#& +'+1=1Be$1302	 	..P	s   +I0 0
J:JJc                (   U R                   S   U R                   S   -  nSUpe[        R                  n[        S[	        US-  5      S-   5       H5  nX-  S:X  d  M  X-  n	X-  n
X-  nX-  n[        X-
  5      nX:  d  M1  UnXpeM7     XPl        X`l        g)zQFinds the right shape to concatenate frames from all environments into one frame.r   rS   g      ?N)r   rJ   r   rj   rd   absr   r   )r.   n_frameshwtarget_video_aspect_ratio	best_rows	best_colsmin_diffr   r   total_heighttotal_widthaspectdiffs                 r/   _get_concat_frame_shape#RecordVideo._get_concat_frame_shapeP  s     ##A&)@)@)CC 	"  !(966!S3/!34D!#'#x"h$36=>?#H+/y 5 $#r1   c                ^   [         R                  " U5      nUR                  u  p#pE[         R                  " U R                  U-  U R
                  U-  U4UR                  S9n[        U5       H<  nXpR
                  -  nXpR
                  -  n	X   XhU-  US-   U-  2X-  U	S-   U-  24'   M>     U$ )z3Concatenates a list of frames into one large frame.rP   rS   )rJ   r_   rb   rf   r   r   rQ   rj   )
r.   framesr   r   r   cgrididxrc_s
             r/   _concat_framesRecordVideo._concat_framesd  s    &!"LLQxx__q $//A"5q9
 ?C&A&B?E{DQ!a%1$bfQ!|&;;< # r1   c                   U R                   (       d   S5       eU R                  R                  5       n[        U[        5      (       d   [        U5      5       e[        U5      U R                  :X  d   eU R                  (       a  US   /nU R                  S:X  d  U R                  S:X  a/  [        U5      nUS   R                  u  p4nU R                  X#U5        U R                  U5      nU R                  R                  U5        g )Nz1Cannot capture a frame, recording wasn't started.r   rF   )r   r)   rM   rI   r   r^   r[   r\   r   r   r   rb   r   r   r   r-   )r.   
envs_framer   r   r   r   concatenated_envs_frames          r/   _capture_frameRecordVideo._capture_frameq  s    ~~RRR~XX__&
*h//Aj1AA/:$--///!!$Q-J??b DOOr$9:H m))GA!((a8"&"5"5j"A##$;<r1   r>   c               ^  > Ub  SU;  d  US   S   (       a  U =R                   S-  sl         U R                  (       a)  U R                  [        S5      :X  a  U R	                  5         U R
                  (       aJ  U R                  U R                   5      (       a*  U R                  U R                   SU R                    35        [        TU ]%  XS9u  p4U R                  (       aC  U R                  5         [        U R                  5      U R                  :  a  U R	                  5         SU l        X44$ )z<Reset the environment and eventually starts a new recording.
reset_maskr   rS   r   	-episode-r>   F)r   r   r   r   stop_recordingr   start_recordingr   r7   rB   r   r[   r   r   )r.   r?   r@   obsinfor<   s        r/   rB   RecordVideo.reset  s     ?l'9W\=RST=UOOq O~~$"3"3uU|"C##%##(<(<T__(M(M$$(8(8'94??BS%TUGMtM=	>>!4''(4+<+<<##%"yr1   c                   U R                   R                  U5      u  p#pEnU =R                  S-  sl        U R                  [        R
                  R                  R                  :X  a  U R                  (       a  U =R                  S-  sl	        U R                  (       a)  U R                  [        S5      :X  a  U R                  5         U R                  (       aJ  U R                  U R                  5      (       a*  U R                  U R                    SU R                   35        US   =(       d    US   U l        OU R                  [        R
                  R                  R"                  :X  a  US   (       d
  US   (       a  U =R                  S-  sl	        U R                  (       a)  U R                  [        S5      :X  a  U R                  5         U R                  (       aJ  U R                  U R                  5      (       a*  U R                  U R                    SU R                   35        U R$                  (       aJ  U R%                  U R                  5      (       a*  U R                  U R                    SU R                   35        U R                  (       aC  U R'                  5         [)        U R*                  5      U R                  :  a  U R                  5         X#XEU4$ )z]Steps through the environment using action, recording observations if :attr:`self.recording`.rS   r   r   r   z-step-)r)   r8   r   r   r!   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r[   r   )r.   r:   r   rewardsterminationstruncationsr   s          r/   r8   RecordVideo.step  s    9=g8N5l#**":":"D"DD!!1$>>d&7&75<&G'')''D,@,@,Q,Q((++,Idoo5FG ".a!BKND  CJJ$<$<$F$FFO{1~OOq O~~$"3"3uU|"C##%##(<(<T__(M(M$$(8(8'94??BS%TU!2!24<<!@!@  D$4$4#5VDLL>!JK>>!4''(4+<+<<##%\<<r1   c                   > [         TU ]  5       nU R                  (       a*  [        U[        5      (       a  U =R
                  U-  sl        [        U R                  5      S:  a  U R                  n/ U l        X!-   $ U$ )ziCompute the render frames as specified by render_mode attribute during initialization of the environment.r   )r7   rM   r   rI   rZ   r   r[   r   )r.   
render_outtmp_historyr<   s      r/   rM   RecordVideo.render  sh    W^%
>>jT::  J. t""#a'--K"$D++r1   c                f   > [         TU ]  5         U R                  (       a  U R                  5         gg)z+Closes the wrapper then the video recorder.N)r7   r   r   r   )r.   r<   s    r/   r   RecordVideo.close  s$    >>! r1   c                `    U R                   (       a  U R                  5         SU l         Xl        g)zkStart a new recording. If it is already recording, stops the current recording before starting the new one.TN)r   r   r   )r.   
video_names     r/   r   RecordVideo.start_recording  s"    >>!%r1   c                   U R                   (       d   S5       e[        U R                  5      S:X  a  [        R                  " S5        O} SSKJn  U" U R                  U R                  S9nU R                  (       a  SOSn[        R                  R                  U R                  U R                    S	35      nUR#                  XTS
9  / U l        SU l         SU l        U R$                  (       a7  U R%                  U R&                  5      (       a  [(        R*                  " 5         ggg! [         a  n[        R                  " S5      UeSnAff = f)z+Stop current recording and saves the video.z7stop_recording was called, but no recording was startedr   z9Ignored saving a video as there were zero frames to save.)ImageSequenceClipr   N)r   barz.mp4)r
   F)r   r[   r   r
   r   "moviepy.video.io.ImageSequenceClipr  rX   r	   r   r   r   r   r   joinr   r   write_videofiler   r   gccollect)r.   r  r   clipmoviepy_loggerr   s         r/   r   RecordVideo.stop_recording  s
   ~~XXX~t##$)KKSTP %T%9%9t?R?RSD%)%8%8TeN77<< 1 1d6F6F5Gt3LMD   =!??tt??JJL  @?  22Ts   
D$ $
E
.EE
c                d    [        U R                  5      S:  a  [        R                  " S5        gg)z.Warn the user in case last video wasn't saved.r   z0Unable to save last video! Did you call close()?N)r[   r   r
   r   r4   s    r/   __del__RecordVideo.__del__  s'    t##$q(KKJK )r1   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r)   zgym.vector.VectorEnvr   r   r   ztuple[int, int]r   boolr   Callable[[int], bool] | Noner   r  r   rd   r   r   r   
int | Noner   r  r   r  )r?   r  r@   r   r   r   )r:   r   r   z9tuple[ObsType, SupportsFloat, bool, bool, dict[str, Any]])r   zRenderFrame | list[RenderFrame])r   r   )r   r   r   r   r   r    r   r   r   rB   r8   rM   r   r   r   r  r   r   r   s   @r/   r   r      s   @ /5"'8<59%#3Gl!l l ,	l
  l 6l 3l l l l l 1l\$(=& %)4!3H	' 0%=%=	B%=N"&2L Lr1   r   )%r   
__future__r   r  r   collections.abcr   r   copyr   typingr   r   numpyrJ   	gymnasiumr!   r	   r
   gymnasium.corer   r   r   gymnasium.errorr   gymnasium.loggerr   gymnasium.vectorr   r   gymnasium.vector.vector_envr   r"   r#   r   r   r   r3   r1   r/   <module>r     sx    D " 	 	 .  %   # 8 8 2 ! 5 1i]CII$C$C iXwLJJII##wLr1   