ó
    �®žjúE  ã                   ó<  • % S r SSKrSSKrSSKrSSKJr  SSKJr  SSKJ	r	  SSK
Jr  SSKrSSKJr  SSKJrJrJr   " S	 S
\\5      r\R,                  " \5      rSr\\   \S'    " S S\5      r " S S\5      rS'S jrSr\\   \S'    Sr \\   \S'    S\RB                  S\4S jr"S\	S\4S jr#S\	S\S\R                  S-  4S jr$S\	S\S\S\S\%\&\\R                  4      4
S  jr'S\	S\S!\(S\%\&\\R                  4      4S" jr) " S# S$5      r* " S% S&5      r+g)(a&  Video frame sampling utilities.

This module is intentionally free of any docling imports. It provides two
frame samplers over a video file, using ffmpeg as the only hard runtime
dependency (ffmpeg is already required by the ASR path).

- ``FixedIntervalFrameSampler`` extracts one frame every N seconds.
- ``SimpleSceneChangeFrameSampler`` probes low-resolution frames and emits a
  representative frame per detected scene using a mean-absolute-difference
  heuristic.

Both return ``VideoFrame`` objects carrying the frame image and its timestamp.
é    N)ÚEnum)ÚBytesIO)ÚPath)ÚFinal)ÚImage)Ú	BaseModelÚ
ConfigDictÚFieldc                   ó    • \ rS rSrSrSrSrSrg)ÚVideoFrameSamplingModeé   z/Frame sampling strategy for the video pipeline.Úfixed_intervalÚscene_change© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__ÚFIXED_INTERVALÚSCENE_CHANGEÚ__static_attributes__r   ó    Ú_/home/mande/repo/quber/.venv/lib/python3.13/site-packages/docling/utils/video_frame_sampling.pyr   r      s   † Ù9à%€NØ!ƒLr   r   zÝFFmpeg is required for video processing but was not found on PATH. Install it with your system package manager (e.g., 'brew install ffmpeg' on macOS, 'apt-get install ffmpeg' on Linux, 'winget install ffmpeg' on Windows).ÚMISSING_FFMPEG_MESSAGEc                   óŠ   • \ rS rSr% Sr\" SS9r\" SSSS9r\	\
S	'   \" SS
S9r\R                  \
S'   \" SSS9r\S-  \
S'   Srg)Ú
VideoFrameé0   z0A single sampled video frame with its timestamp.T©Úarbitrary_types_allowed.r   zSeconds from video start.)ÚgeÚdescriptionÚ	timestampzThe decoded frame image.)r"   ÚimageNz+Scene index if produced by a scene sampler.Úscene_idr   )r   r   r   r   r   r	   Úmodel_configr
   r#   ÚfloatÚ__annotations__r$   r   r%   Úintr   r   r   r   r   r   0   sT   ‡ Ù:á°dÑ;€Lá˜S QÐ4OÑP€IˆuÓPÙ˜sÐ0JÑK€Eˆ5�;‰;ÓKÙ ØÐGñ€Hˆc�D‰jö r   r   c                   ót   • \ rS rSr% Sr\" SS9r\\S'   \	" SSS9r
\\S	'   \	" SSS9r\\S
'   Sr\S-  \S'   Srg)Ú
VideoSceneé<   z.A contiguous time window treated as one scene.Tr   r%   .r   )r!   Ú
start_timeÚend_timeNÚrepresentative_framer   )r   r   r   r   r   r	   r&   r)   r(   r
   r-   r'   r.   r/   r   r   r   r   r   r+   r+   <   sF   ‡ Ù8á°dÑ;€LàƒMÙ˜c aÑ(€J�Ó(Ù˜C AÑ&€HˆeÓ&Ø.2Ð˜* tÑ+Ö2r   r+   Úreturnc                  óP   • [         R                  " S5      c  [        [        5      eg )NÚffmpeg)ÚshutilÚwhichÚRuntimeErrorr   r   r   r   Ú_require_ffmpegr6   G   s"   € Ü‡|‚|�HÓÑ%ÜÔ1Ó2Ð2ð &r   gú~j¼t“ˆ?Ú_AUTO_PROMINENCE_FLOORg      @Ú_AUTO_PROMINENCE_KÚdiffsc                 óä   • [        [        R                  " U 5      5      n[        [        R                  " [        R                  " X-
  5      5      5      S-  n[	        [
        U[        U-  -   5      $ )uT  Adapt the scene-cut threshold to how busy the video is.

Uses the median frame difference as the ambient-motion floor and the
(robust) median absolute deviation as its spread, so the threshold rises
automatically for high-motion footage â€” ignoring hand-waving and body
movement â€” and drops toward the floor for static screens, catching subtle
cuts. Robust statistics are used so the cut spikes themselves do not inflate
the estimate (unlike a plain standard deviation).

Args:
    diffs: Frame-to-frame difference signal.

Returns:
    The calibrated prominence threshold for peak detection.
g)ËÇº¸÷?)r'   ÚnpÚmedianÚabsÚmaxr7   r8   )r9   r<   Úmads      r   Ú_auto_prominencer@   X   sS   € ô  ”2—9’9˜UÓ#Ó$€FÜ
”—	’	œ"Ÿ&š& ¡Ó0Ó1Ó
2°VÑ
;€CÜÔ% vÔ0BÀSÑ0HÑ'HÓIÐIr   Ú
video_pathc                 ó
  • [         R                  " S5      c  g [        R                  " SSSSSSS[	        U 5      /S	S	S	S
9n[        UR                  R                  5       5      $ ! [        R                  [        4 a     gf = f)zFReturn the video duration in seconds using ffprobe, or 0.0 on failure.Úffprobeç        z-vÚerrorz-show_entrieszformat=durationz-ofz"default=noprint_wrappers=1:nokey=1T)Úcapture_outputÚtextÚcheck)
r3   r4   Ú
subprocessÚrunÚstrr'   ÚstdoutÚstripÚCalledProcessErrorÚ
ValueError)rA   Úouts     r   Ú_probe_durationrQ   m   sŠ   € ä‡|‚|�IÓÑ&ØðÜ�nŠnàØØØØ!ØØ4Ü�J“ð	ð  ØØñ
ˆô �S—Z‘Z×%Ñ%Ó'Ó(Ð(øÜ×)Ñ)¬:Ð6ó Ùðús   šA
A% Á%BÂBr#   c                 óì  • [         R                  " SSSUS S[        U 5      SSSS	S
SS/SSS9nUR                  S:w  d  UR                  (       d@  [
        R                  SUUR                  UR                  R                  SS5      SS 5        g [        R                  " [        UR                  5      5      R                  S5      $ ! [         a   n[
        R                  SX5         SnAgSnAff = f)z‰Extract a single frame at ``timestamp`` as a PIL image via ffmpeg.

Returns None if ffmpeg produced no output (e.g. timestamp past end).
r2   ú-nostdinú-ssú.3fú-iz	-frames:vÚ1ú-fÚ
image2pipeú-vcodecÚpngÚ-TF©rF   rH   r   z8Frame extraction at %.3fs produced no output (rc=%s): %súutf-8Úreplaceé8ÿÿÿNÚRGBz-Failed to decode extracted frame at %.3fs: %s)rI   rJ   rK   Ú
returncoderL   Ú_logÚdebugÚstderrÚdecoder   Úopenr   ÚconvertÚ	Exception)rA   r#   ÚprocÚexcs       r   Ú_extract_framerl   †   så   € ô
 �>Š>àØØØ˜ˆoØÜ�
‹OØØØØØØØð	
ð Øñ#€Dð& ‡�˜!Ó 4§;§;Ü�
‰
ØFØØ�O‰OØ�K‰K×Ñ˜w¨	Ó2°4°5Ð9ô		
ð ðÜ�zŠzœ' $§+¡+Ó.Ó/×7Ñ7¸Ó>Ð>øÜó Ü�
‰
ÐBÀIÔSÜûðús   Â7C	 Ã	
C3ÃC.Ã.C3ÚstartÚdurationÚfpsc                 ó2  • [         R                  " SSSUS S[        U 5      SUS SSU 3S	S
SSS/SSS9nUR                  S:w  d  UR                  (       dA  [
        R                  SUUR                  UR                  R                  SS5      SS 5        / $ / nUR                  nSn[        [        U5      5       Vs/ s H  o†R                  Xx5      (       d  M  UPM     n	n[        U	5       Hr  u  p«U
S-   [        U	5      :  a  XšS-      O
[        U5      n [        R                  " [        XkU 5      5      R!                  S5      nUR%                  XU-  -   U45        Mt     U$ s  snf ! ["         a!  n[
        R                  SX®5         SnAM£  SnAff = f)zÍDecode ``[start, start + duration]`` once at ``fps``, full resolution.

Single ffmpeg spawn per call, seeking to ``start`` before decoding
(fast input seek) rather than spawning one process per timestamp.
r2   rS   rT   rU   rV   z-tú-vfúfps=rX   rY   rZ   r[   r\   TFr]   r   z9Range frame probe at %.3fs produced no output (rc=%s): %sr^   r_   r`   Ns   ‰PNG

é   ra   z,Failed to decode frame %d in range probe: %s)rI   rJ   rK   rb   rL   rc   rd   re   rf   ÚrangeÚlenÚ
startswithÚ	enumerater   rg   r   rh   ri   Úappend)rA   rm   rn   ro   rj   ÚframesÚbufÚsigÚiÚoffsetsÚidxÚoffÚendÚimgrk   s                  r   Ú_extract_frames_ranger‚   ­   s‰  € ô �>Š>àØØØ�SˆkØÜ�
‹OØØ˜ˆnØØ�3�%ˆLØØØØØð	
ð" Øñ'€Dð* ‡�˜!Ó 4§;§;Ü�
‰
ØGØØ�O‰OØ�K‰K×Ñ˜w¨	Ó2°4°5Ð9ô		
ð ˆ	à.0€FØ
�+‰+€Cà
€CÜ¤ C£œ/ÓDš/�Q¯^©^¸C×-C�q™/€GÐDÜ˜gÖ&‰ˆØ"%¨¡'¬C°«LÓ"8ˆg˜A‘gÒ¼cÀ#»hˆð	Ü—*’*œW S¨S \Ó2Ó3×;Ñ;¸EÓBˆCð 	�‰�u S™yÑ(¨#Ð.Ö/ñ 'ð €Mùò Eøô
 ó 	Ü�J‰JÐEÀsÔPÝûð	ús$   Â>E&ÃE&Ä0E+Å+
FÅ5FÆFÚsizec                 ó
  • [         R                  " SSS[        U 5      SSU SU SU 3SS	S
SS/SSS9nUR                  S:w  d  UR                  (       d@  [
        R                  SUR                  UR                  R                  SS5      SS 5        / $ X"-  S-  nUR                  n[        U5      U-  n/ n[        U5       H<  nXXU-  US-   U-   n	UR                  X�-  [        R                  " SX"4U	5      45        M>     U$ )a@  Decode the whole video once at ``fps``, returning ``(timestamp, image)`` pairs.

Uses a single ffmpeg pass emitting downscaled raw RGB frames, which is far
cheaper than spawning one ffmpeg process per timestamp (each spawn re-opens
and re-seeks the file). Frames are square ``size`` x ``size`` thumbnails;
the timestamp of frame ``i`` is ``i / fps``.

Args:
    video_path: Path to the source video.
    fps: Sampling rate for the decode pass.
    size: Width and height, in pixels, of the square thumbnails.

Returns:
    ``(timestamp, image)`` pairs in chronological order.
r2   rS   rV   rq   rr   z,scale=Ú:rX   Úrawvideoz-pix_fmtÚrgb24r\   TFr]   r   z0Batch frame probe produced no output (rc=%s): %sr^   r_   r`   Né   rs   ra   )rI   rJ   rK   rb   rL   rc   rd   re   rf   ru   rt   rx   r   Ú	frombytes)
rA   ro   rƒ   rj   Úframe_bytesrz   Úcountry   r|   Úchunks
             r   Ú_extract_frames_gridr�   ã   s  € ô$ �>Š>àØØÜ�
‹OØØ�3�%�w˜t˜f A d VÐ,ØØØØØð	
ð Øñ€Dð" ‡�˜!Ó 4§;§;Ü�
‰
Ø>Ø�O‰OØ�K‰K×Ñ˜w¨	Ó2°4°5Ð9ô	
ð
 ˆ	à‘+ ‘/€KØ
�+‰+€CÜ�‹H˜Ñ#€EØ.0€FÜ�5Ž\ˆØ˜‘O q¨1¡u°Ñ&;Ð<ˆØ�‰�q‘w¤§¢°¸°|ÀUÓ KÐLÖMñ ð €Mr   c                   óP   • \ rS rSrSr  SS\S\S-  4S jjrS\S\	\
   4S	 jrS
rg)ÚFixedIntervalFrameSampleri  z;Sample one frame every ``interval_seconds`` from time zero.NÚinterval_secondsÚ
max_framesc                 óf   • US::  a  [        S5      eUb  US::  a  [        S5      eXl        X l        g )Nr   zinterval_seconds must be > 0úmax_frames must be > 0 when set)rO   r�   r‘   )Úselfr�   r‘   s      r   Ú__init__Ú"FixedIntervalFrameSampler.__init__  s;   € ð
 ˜qÓ ÜÐ;Ó<Ð<ØÑ! j°A£oÜÐ>Ó?Ð?Ø 0ÔØ$�r   rA   r0   c                 ó,  • [        5         [        U5      n/ nSnUS:X  d  XB:  ao  U R                  b  [        U5      U R                  :¼  a   U$ [	        X5      nUc   U$ UR                  [        XES95        X@R                  -  nUS:X  a  Mh  XB:  a  Mo  U$ )NrD   )r#   r$   )r6   rQ   r‘   ru   rl   rx   r   r�   )r”   rA   rn   ry   Útr$   s         r   ÚsampleÚ FixedIntervalFrameSampler.sample'  sš   € ÜÔÜ" :Ó.ˆà#%ˆØˆà˜#‹o £Ø�‰Ñ*¬s°6«{¸d¿o¹oÓ/MØð ˆô # :Ó1ˆEØ‰}Øð ˆð �M‰Mœ*¨qÑ>Ô?Ø×&Ñ&Ñ&ˆAð ˜#�o ¥ð ˆr   )r�   r‘   )g      $@N)r   r   r   r   r   r'   r)   r•   r   Úlistr   r™   r   r   r   r   r�   r�     s@   † ÙEð #'Ø!%ñ
%àð
%ð ˜$‘Jõ
%ð ð ¨$¨zÑ*:÷ r   r�   c                   ój  • \ rS rSrSr        SS\S\S-  S\S-  S\S\S-  S	\S
\S\4S jjrS\S\	\
\\R                  4      4S jr\S\R                  S\R                  S\4S j5       r\S\R                  S\4S j5       rS\S\S\S\S\S-  4
S jrS\S\	\   4S jrS\S\	\   4S jrSrg)ÚSimpleSceneChangeFrameSampleri9  ua  Detect scenes via local peak detection on the frame-difference signal.

No global threshold required. The sampler:
1. Probes the video at ``probe_fps`` (small RGB thumbnails).
2. Computes mean-absolute pixel difference between consecutive frames.
3. Smooths the resulting 1-D signal with a moving average.
4. Detects scene boundaries as local peaks using scipy.signal.find_peaks
   with a prominence criterion â€” self-calibrating per video, no manual
   threshold needed.
5. Selects the sharpest frame in a window around each scene midpoint
   as the representative keyframe, avoiding motion-blurred frames.
NÚ	probe_fpsÚ
prominenceÚcuts_per_minuteÚmin_scene_duration_secondsr‘   Ú
probe_sizeÚsmooth_windowÚsharpness_candidatesc	                 óø   • US::  a  [        S5      eUb  US:  a  [        S5      eUS:  a  [        S5      eUb  US::  a  [        S5      eXl        X l        X0l        X@l        XPl        X`l        Xpl        X€l        g )Nr   zprobe_fps must be > 0zprominence must be >= 0z'min_scene_duration_seconds must be >= 0r“   )	rO   rž   rŸ   r    r¡   r‘   r¢   r£   r¤   )	r”   rž   rŸ   r    r¡   r‘   r¢   r£   r¤   s	            r   r•   Ú&SimpleSceneChangeFrameSampler.__init__G  s‡   € ð ˜‹>ÜÐ4Ó5Ð5ØÑ! j°1£nÜÐ6Ó7Ð7Ø%¨Ó)ÜÐFÓGÐGØÑ! j°A£oÜÐ>Ó?Ð?Ø"ŒØ$ŒØ.ÔØ*DÔ'Ø$ŒØ$ŒØ*ÔØ$8Õ!r   rA   r0   c                 óB   • [        XR                  U R                  5      $ )zIExtract downscaled RGB probe frames at probe_fps in a single decode pass.)r�   rž   r¢   )r”   rA   s     r   Ú_probe_framesÚ+SimpleSceneChangeFrameSampler._probe_framesc  s   € ä# J·±ÀÇÁÓPÐPr   ÚaÚbc                 óH  • [         R                  " U [         R                  S9n[         R                  " U[         R                  S9nUR                  UR                  :w  d  UR                  S:X  a  g[        [         R                  " X#-
  5      R                  5       5      S-  $ )z<Normalized mean absolute difference of two images in [0, 1].©Údtyper   rD   g     ào@)r;   ÚasarrayÚint16Úshaperƒ   r'   r=   Úmean)rª   r«   Úarr_aÚarr_bs       r   Ú_mean_abs_diffÚ,SimpleSceneChangeFrameSampler._mean_abs_diffg  sm   € ô —
’
˜1¤B§H¡HÑ-ˆÜ—
’
˜1¤B§H¡HÑ-ˆØ�;‰;˜%Ÿ+™+Ó%¨¯©°q«ØÜ”R—V’V˜E™MÓ*×/Ñ/Ó1Ó2°UÑ:Ð:r   r$   c                 ó   • [         R                  " U R                  S5      [         R                  S9nUSS2SS24   USS2SS24   -   USS2SS24   -   USS2SS24   -   SUSS2SS24   -  -
  n[	        [         R
                  " U5      5      $ )	uH   Laplacian variance â€” higher = sharper, used to avoid blurry keyframes.ÚLr­   Néþÿÿÿrs   éÿÿÿÿé   é   )r;   r¯   rh   Úfloat32r'   Úvar)r$   ÚgrayÚlaps      r   Ú
_sharpnessÚ(SimpleSceneChangeFrameSampler._sharpnessp  s´   € ô �zŠz˜%Ÿ-™-¨Ó,´B·J±JÑ?ˆà��"��a˜�d�‰OØ�1‘2�q˜�t�8‰nñà�1�R�4˜˜"˜�9‰oñð �1�R�4˜™�8‰nñð �$�q˜�t˜Q˜r˜T�zÑ"Ñ"ñ	#ð 	ô ”R—V’V˜C“[Ó!Ð!r   rm   r€   r%   c                 óz  • X#-   S-  nX2-
  S-  S-  n[        X%U-
  5      n[        X5U-   5      n[        X‡-
  S5      n	U R                  n
U	S:X  d  U
S::  a  [        X5      nU(       a
  [	        X[US9$ S$ U
S-
  U	-  n[        XXœ5      nSnSnU H+  u  nnU R                  U5      nUU:”  d  M  Un[	        UX´S9nM-     U$ )a  Pick the sharpest frame in a window centred on the scene midpoint.

Decodes the whole candidate window in a single ffmpeg spawn (full
resolution, sampled at ``sharpness_candidates`` evenly spaced points)
instead of spawning one ffmpeg process per candidate timestamp.

Args:
    video_path: Path to the source video.
    start: Scene start time, in seconds.
    end: Scene end time, in seconds.
    scene_id: Index of the scene this frame represents.

Returns:
    The sharpest candidate frame, or None if none could be decoded.
ç       @gš™™™™™Ù?rD   rs   )r#   r$   r%   Ng      ð¿)r>   Úminr¤   rl   r   r‚   rÁ   )r”   rA   rm   r€   r%   ÚmidÚhalfÚwindow_startÚ
window_endÚwindow_durationÚnr�   ro   Ú
candidatesÚ
best_frameÚ
best_scorer˜   Úscores                     r   Ú_best_frameÚ)SimpleSceneChangeFrameSampler._best_frame}  sð   € ð$ ‰{˜cÑ!ˆØ‘˜sÑ" SÑ(ˆÜ˜5¨¡*Ó-ˆÜ˜ D™jÓ)ˆ
Ü˜jÑ7¸Ó=ˆØ×%Ñ%ˆà˜cÓ! Q¨!£VÜ  Ó1ˆCæKN”
 S¸hÑGðØTXðð
 �1‰u˜Ñ'ˆÜ*Ø oó
ˆ
ð )-ˆ
Øˆ
Û ‰FˆAˆsØ—O‘O CÓ(ˆEØ�zÕ!Ø"�
Ü'°!¸3ÑR’
ñ	 !ð
 Ðr   c                 ó   • U R                  U5      n[        U5      S:  a  / $ U Vs/ s H  o3S   PM	     nn[        R                  " [	        [        U5      S-
  5       Vs/ s H"  nU R                  X%   S   X%S-      S   5      PM$     sn5      n[        SU R                  5      n[        R                  " U[        R                  " U5      U-  SS9n[        S[        U R                  U R                  -  5      5      n	U R                  b€  [        U	[        SU R                  -  U R                  -  5      5      n
[        [        R                  " US5      5      nSSKJn  U" XŠUS	9u  pÞ[$        R'                  S
U
U[        U5      5        OJU R(                  b  U R(                  nO[+        U5      n[$        R'                  SU5        SSKJn  U" X�U	S9u  pÞU Vs/ s H  o4U   U R                  :¼  d  M  UPM     nnUS   /U Vs/ s H  o4U   PM	     sn-   nUS   n/ n[-        U5       H<  u  nnUS-   [        U5      :  a  UUS-      OUnUR/                  [1        UUUS95        M>     U$ s  snf s  snf s  snf s  snf )zBDetect scene boundaries using local peak detection on frame diffs.r»   r   rs   Úsame)Úmodeg      N@éK   )Ú
find_peaks)ÚdistancerŸ   z=Cuts/min mode: interval=%d frames, noise_floor=%.4f, peaks=%dz Prominence mode: prominence=%.4f)rŸ   r×   rº   )r%   r-   r.   )r¨   ru   r;   Úarrayrt   rµ   r>   r£   ÚconvolveÚonesr)   r¡   rž   r    r'   Ú
percentileÚscipy.signalrÖ   rc   rd   rŸ   r@   rw   rx   r+   )r”   rA   ÚprobesÚpÚ
timestampsr|   r9   ÚwÚsmoothedÚmin_distÚtarget_intervalÚnoise_floorrÖ   ÚpeaksÚ_rŸ   Úvalid_peaksÚ
boundariesr.   Úscenesr~   rm   Ústops                          r   Údetect_scenesÚ+SimpleSceneChangeFrameSampler.detect_scenes«  sg  € à×#Ñ# JÓ/ˆÜˆv‹;˜‹?ØˆIá$*Ó+¢F˜q˜”d¡Fˆ
Ð+Ü—’ô œs 6›{¨Q™Ô/óâ/�Að ×#Ñ# F¡I¨a¡L°&¸Q¹±-ÀÑ2BÖCÙ/ñó
ˆô ��4×%Ñ%Ó&ˆÜ—;’;˜u¤b§g¢g¨a£j°1¡n¸6ÑBˆä�qœ#˜d×=Ñ=ÀÇÁÑNÓOÓPˆØ×ÑÑ+Ü!Øœ#˜t d×&:Ñ&:Ñ:¸d¿n¹nÑLÓMóˆOô  ¤§¢¨h¸Ó ;Ó<ˆKõñ "Ø¸{ñ‰HˆEô �J‰JØOØØÜ�E“
õ	ð �‰Ñ*Ø!Ÿ_™_‘
ä-¨eÓ4�
Ü�J‰JÐ9¸:ÔFõñ " (ÈHÑU‰HˆEñ ó
Ú�!¨1¡°×1PÑ1PÑ P�A‘uð 	ð 
ð ! ‘m�_¹{Ó'Kº{¸!°1¬¹{Ñ'KÑKˆ
Ø˜b‘>ˆà#%ˆÜ# JÖ/‰JˆC�Ø*-°©'´C¸
³OÓ*C�:˜c A™gÒ&ÈˆDØ�M‰Mœ*¨c¸eÈdÑSÖTñ 0ð ˆùòk ,ùòùòR
ùò (Ls   §I,Á )I1ÇI6Ç4I6ÈI;c                 ó>  • [        5         U R                  U5      n/ nU Hy  nU R                  b  [        U5      U R                  :¼  a    U$ U R	                  XR
                  UR                  UR                  5      nUc  Mb  XTl        UR                  U5        M{     U$ )z9Sample one sharp representative frame per detected scene.)
r6   rë   r‘   ru   rÐ   r-   r.   r%   r/   rx   )r”   rA   ré   ry   ÚsceneÚframes         r   r™   Ú$SimpleSceneChangeFrameSampler.sampleè  s’   € äÔØ×#Ñ# JÓ/ˆØ#%ˆÛˆEØ�‰Ñ*¬s°6«{¸d¿o¹oÓ/MØð ˆð ×$Ñ$Ø×,Ñ,¨e¯n©n¸e¿n¹nóˆEð Ó Ø-2Ô*Ø—‘˜eÖ$ñ ð ˆr   )r    r‘   r¡   rž   r¢   rŸ   r¤   r£   )g      ð?NNrÄ   Né@   rs   é   )r   r   r   r   r   r'   r)   r•   r   r›   Útupler   r¨   Ústaticmethodrµ   rÁ   r   rÐ   r+   rë   r™   r   r   r   r   r�   r�   9  sd  † ñð Ø#'Ø(,Ø,/Ø!%ØØØ$%ñ9àð9ð ˜D‘Lð9ð  ™ð	9ð
 %*ð9ð ˜$‘Jð9ð ð9ð ð9ð "õ9ð8Q¨ð Q°°e¸EÀ5Ç;Á;Ð<NÑ6OÑ1Pô Qð ð;˜%Ÿ+™+ð ;¨%¯+©+ð ;¸%ó ;ó ð;ð ð
"˜%Ÿ+™+ð 
"¨%ó 
"ó ð
"ð,Øð,Ø',ð,Ø38ð,ØDGð,à	�dÑ	ô,ð\;¨ð ;°°jÑ1Aô ;ðz ð ¨$¨zÑ*:÷ r   r�   )r0   N),r   Úloggingr3   rI   Úenumr   Úior   Úpathlibr   Útypingr   Únumpyr;   ÚPILr   Úpydanticr   r	   r
   rK   r   Ú	getLoggerr   rc   r   r(   r   r+   r6   r7   r'   r8   Úndarrayr@   rQ   rl   r›   ró   r‚   r)   r�   r�   r�   r   r   r   Ú<module>rÿ      s�  ðòó Û Û Ý Ý Ý Ý ã Ý ß 1Ñ 1ô"˜S $ô "ð ×Ò˜Ó"€ðð ˜˜c™
ó ô	�ô 	ô3�ô 3ô3ð (-Ð ˜˜e™Ó ,ðPð $'Ð �E˜%‘LÓ &ðKðJ˜BŸJ™Jð J¨5ô Jð* ð ¨ô ð2$˜tð $°ð $¸%¿+¹+ÈÑ:Lô $ðN3Øð3Ø"ð3Ø.3ð3Ø:?ð3à	ˆ%��u—{‘{Ð"Ñ
#Ñ$ô3ðl2Øð2Ø ð2Ø(+ð2à	ˆ%��u—{‘{Ð"Ñ
#Ñ$ô2÷jñ ÷B}ò }r   