
    ^jB                       d dl mZ d dlZd dlZd dlZd dlZd dlZd dlZd dlm	Z	 d dl
mZmZ d dlmZ d dlmZmZmZ d dlmZ d dlZd dlZd dlmZ d dlmZ d d	lmZ  ee      Ze G d
 d             Z  G d d      Z!ddZ"	 d	 	 	 	 	 	 	 	 	 ddZ#	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZ$ddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ% G d d      Z&y)    )annotationsN)deque)Callable	Generator)	dataclass)EmptyFullQueue)Any)tqdm)_get_loggerc                  b    e Zd ZU dZded<   ded<   ded<   dZded	<   edd
       Zedd       Z	y)	VideoInfoa  
    A class to store video information, including width, height, fps and
        total number of frames.

    Attributes:
        width: width of the video in pixels
        height: height of the video in pixels
        fps: frames per second of the video as a float. Common values include
            23.976, 24.0, 25.0, 29.97, 30.0, 59.94, and 60.0.
        total_frames: total number of frames in the video,
            default is None

    Examples:
        ```python
        import supervision as sv

        video_info = sv.VideoInfo.from_video_path(video_path="<SOURCE_VIDEO_FILE>")

        video_info
        # VideoInfo(width=3840, height=2160, fps=25.0, total_frames=538)

        video_info.resolution_wh
        # (3840, 2160)
        ```
    intwidthheightfloatfpsN
int | Nonetotal_framesc                   t        j                  |      }|j                         st        d|       t	        |j                  t         j                              }t	        |j                  t         j                              }t        |j                  t         j                              }t	        |j                  t         j                              }|j                          t        ||||      S )NCould not open video at )cv2VideoCaptureisOpened	Exceptionr   getCAP_PROP_FRAME_WIDTHCAP_PROP_FRAME_HEIGHTr   CAP_PROP_FPSCAP_PROP_FRAME_COUNTreleaser   )cls
video_pathvideor   r   r   r   s          b/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/supervision/utils/video.pyfrom_video_pathzVideoInfo.from_video_path:   s      ,~~6zlCDDEIIc6678UYYs889:EIIc../0599S%=%=>?\::    c                2    | j                   | j                  fS N)r   r   selfs    r&   resolution_whzVideoInfo.resolution_whG   s    zz4;;&&r(   )r$   strreturnr   )r/   ztuple[int, int])
__name__
__module____qualname____doc____annotations__r   classmethodr'   propertyr-    r(   r&   r   r      sH    4 JK	J#L*#
; 
; ' 'r(   r   c                  B    e Zd ZdZdddZd	dZd
dZ	 	 	 	 	 	 	 	 ddZy)	VideoSinka  
    Context manager that saves video frames to a file using OpenCV.

    Attributes:
        target_path: The path to the output file where the video will be saved.
        video_info: Information about the video resolution, fps,
            and total frame count.
        codec: FOURCC code for video format

    Example:
        ```python
        import supervision as sv

        video_info = sv.VideoInfo.from_video_path("<SOURCE_VIDEO_PATH>")
        frames_generator = sv.get_video_frames_generator("<SOURCE_VIDEO_PATH>")

        with sv.VideoSink(target_path="<TARGET_VIDEO_PATH>", video_info=video_info) as sink:
            for frame in frames_generator:
                sink.write_frame(frame=frame)
        ```
    c                <    || _         || _        || _        d | _        y r*   )target_path
video_info_VideoSink__codec_VideoSink__writer)r,   r;   r<   codecs       r&   __init__zVideoSink.__init__c   s    &$r(   c                   	 t        j                  | j                   | _        t        j                  | j                  | j                  | j                  j                  | j                  j                        | _        | S # t        $ r@}t
        j                  dt        |             t        j                  d | _        Y d }~d }~ww xY w)Nz%s. Defaulting to mp4v...mp4v)r   VideoWriter_fourccr=   _VideoSink__fourcc	TypeErrorloggerwarningr.   VideoWriterr;   r<   r   r-   r>   )r,   es     r&   	__enter__zVideoSink.__enter__i   s    	<22DLLADM MMOOOO))	
   	<NN6A?22F;DMM	<s   !A> >	C6CCc                T    | j                   | j                   j                  |       yy)z
        Writes a single video frame to the target video file.

        Args:
            frame: The video frame to be written to the file. The frame
                must be in BGR color format.
        N)r>   write)r,   frames     r&   write_framezVideoSink.write_framew   s%     ==$MM& %r(   c                R    | j                   | j                   j                          y y r*   )r>   r"   )r,   exc_type	exc_valueexc_tracebacks       r&   __exit__zVideoSink.__exit__   s#     ==$MM!!# %r(   N)rB   )r;   r.   r<   r   r?   r.   )r/   r9   )rM   znpt.NDArray[np.uint8]r/   None)rP   ztype[BaseException] | NonerQ   zBaseException | NonerR   r   r/   rT   )r0   r1   r2   r3   r@   rJ   rN   rS   r7   r(   r&   r9   r9   L   sA    ,	'$,$ ($ 	$
 
$r(   r9   c                   t        j                  d      }|t        j                  d       yd}	 t	        j
                  t        j                  j                  |      d   t        j                  j                  t        j                  j                  |                  \  }}t        j                  |       t        j                  |dddd	d
|d
| ddddddddd|gt        j                  t        j                  d      }|j                   dk7  r|j"                  j%                  d      j'                         }t        j                  d|j                   |rd| nd       	 |6t        j                  j)                  |      rt        j*                  |       yyyt        j,                  ||       |6t        j                  j)                  |      rt        j*                  |       yyy# t.        $ r }t        j                  d|       Y d}~]d}~ww xY w# |6t        j                  j)                  |      rt        j*                  |       w w w xY w)zMux audio from `source_path` into `video_path` in-place using ffmpeg.

    Args:
        source_path: Path to the original video file containing the audio stream.
        video_path: Path to the video-only file to be updated with audio.
    ffmpegNzcffmpeg not found on PATH. Audio will not be preserved. Install ffmpeg to enable audio preservation.   )suffixdirz-yz	-loglevelerrorz-nostatsz-iz-c:vcopyz-c:az-mapz0:v:0z1:a:0?z	-shortesti,  )stdoutstderrtimeoutr   replace)errorszTffmpeg failed to mux audio (return code %d)%s. The output video will not have audio.z:  z:Audio muxing failed: %s. Output video will not have audio.)shutilwhichrF   rG   tempfilemkstempospathsplitextdirnameabspathclose
subprocessrunDEVNULLPIPE
returncoder]   decodestripexistsremover_   r   )source_pathr$   ffmpeg_pathtmp_pathtmp_fdresult
stderr_msgexcs           r&   
_mux_audior|      s    ,,x(K;	
 	H0 #++77##J/2
 ;<
 	'* %%??1
4 !--Y-?EEGJNN8!!%/"ZL!R	  BGGNN8$<IIh %= 	

8Z( BGGNN8$<IIh %=  
H#	
 	


 BGGNN8$<IIh %=s0   D2G, G, ,	H5HH HH :IFc                   t        j                  |       }|j                         st        d|        t	        |j                  t         j                              }|||kD  rt        d      t        |d      }|t        ||      n|}|r$|dkD  rD|j                         }|sn1|dz  }|dkD  rn%|dkD  r |j                  t         j                  |       |||fS )Nr   zRequested frames are outboundr   rW   )r   r   r   r   r   r   r!   maxmingrabsetCAP_PROP_POS_FRAMES)ru   startenditerative_seekr%   r   successs          r&   _validate_and_setup_videor      s     [)E>>2;-@AAuyy!9!9:;L
3-788qME$'O#c<
 CaijjlGQJE	 ai
 
		#))51%r(   c              #     K   t        | |||      \  }}}|}	 |j                         \  }}|r||k\  rn3|| t        |dz
        D ]  }	|j                         }|r n ||z  }N|j	                          yw)a  
    Get a generator that yields the frames of the video.

    Args:
        source_path: The path of the video file.
        stride: Indicates the interval at which frames are returned,
            skipping stride - 1 frames between each.
        start: Indicates the starting position from which
            video should generate frames
        end: Indicates the ending position at which video
            should stop generating frames. If None, video will be read to the end.
        iterative_seek: If True, the generator will seek to the
            `start` frame by grabbing each frame, which is much slower. This is a
            workaround for videos that don't open at all when you set the `start` value.

    Returns:
        A generator that yields the
            frames of the video.

    Examples:
        ```python
        import supervision as sv

        for frame in sv.get_video_frames_generator(source_path="<SOURCE_VIDEO_PATH>"):
            ...
        ```
    NrW   )r   readranger   r"   )
ru   strider   r   r   r%   frame_positionr   rM   _s
             r&   get_video_frames_generatorr      s     D 2UCE5# N
.C/Kvz" 	AjjlG	 	&   
MMOs   AA7A7    zProcessing video)
max_framesprefetchwriter_buffershow_progressprogress_messagepreserve_audioc                   t         j                         }	t        |	j                  xs d      n|	j                  xs d}
t	        |      t	        |      d fd}dfd}t        j                  |d      }t        ||		      5 }t        j                  ||fd
      }|j                          |j                          t        |
| |      }d}d}	 	 j                         }|d}n2|\  }}	  |||      }j                  |       |j                  d       G	 j                  dd       |s	 	 j                  d      }|n	 |j#                  d       |j#                  d       |j%                          ||	 ddd       |r4j!                         rt&        j)                  d       yt+         |       yy# t        $ r}|}Y d}~d}~ww xY w# t        $ r Y w xY w# t        $ r |j!                         sY Y w xY w# 	 j                  dd       n# t        $ r Y nw xY w|s:	 	 j                  d      }|n#n!# t        $ r |j!                         sY nY 5w xY w9|j#                  d       |j#                  d       |j%                          ||w xY w# 1 sw Y   &xY w)uh
  
    Process video frames asynchronously using a threaded pipeline.

    This function orchestrates a three-stage pipeline to optimize video processing
    throughput:

    1. Reader thread: Continuously reads frames from the source video file and
       enqueues them into a bounded queue (`frame_read_queue`). The queue size is
       limited by the `prefetch` parameter to control memory usage.
    2. Main thread (Processor): Dequeues frames from `frame_read_queue`, applies the
       user-defined `callback` function to process each frame, then enqueues the
       processed frames into another bounded queue (`frame_write_queue`) for writing.
       The processing happens in the main thread, simplifying use of stateful objects
       without synchronization.
    3. Writer thread: Dequeues processed frames from `frame_write_queue` and writes
       them sequentially to the output video file.

    Args:
        source_path: Path to the input video file.
        target_path: Path where the processed video will be saved.
        callback: Function called for
            each frame, accepting the frame as a numpy array and its zero-based index,
            returning the processed frame.
        max_frames: Optional maximum number of frames to process.
            If None, the entire video is processed (default).
        prefetch: Maximum number of frames buffered by the reader thread.
            Controls memory use; default is 32.
        writer_buffer: Maximum number of frames buffered before writing.
            Controls output buffer size; default is 32.
        show_progress: Whether to display a tqdm progress bar during processing.
            Default is False.
        progress_message: Description shown in the progress bar.
        preserve_audio: If True, copy the audio stream from `source_path` into
            `target_path` after frame processing. Requires `ffmpeg` on PATH
            (e.g. `apt install ffmpeg`, `brew install ffmpeg`). If ffmpeg is
            not found or the mux step fails, a warning is logged and the output
            video is saved without audio — no exception is raised. Audio is
            truncated to match the processed video duration. Default is False.

    Returns:
        None

    Example:
        ```python
        import supervision as sv
        from rfdetr import RFDETRMedium

        model = RFDETRMedium()

        def callback(frame, frame_index):
            return model.predict(frame)

        sv.process_video(
            source_path="source.mp4",
            target_path="target.mp4",
            callback=callback,
            preserve_audio=True,
        )
        ```
    )r$   Nr   )maxsizec                     t              } t        |       D ]  \  }}j                  ||f        j                  d        y )N)ru   r   )r   	enumerateput)frame_generatorframe_indexrM   frame_read_queuer   ru   s      r&   reader_threadz$process_video.<locals>.reader_threadq  sO    4#
 #,O"< 	7K  +u!56	7T"r(   c                R    	 j                         }|y | j                  |       &)N)rM   )r   rN   )
video_sinkrM   frame_write_queues     r&   writer_threadz$process_video.<locals>.writer_threadz  s2    %))+E}"""/	 r(   T)targetdaemon)r;   r<   )r   argsr   )totaldisabledescFrW   )r^   
   zdWriter thread did not finish in time; skipping audio mux to avoid reading an incomplete output file.)ru   r$   r/   rT   )r   r9   r/   rT   )r   r'   r   r   r
   	threadingThreadr9   r   r   r   r   updater   r	   r   is_alivejoinrk   rF   rG   r|   )ru   r;   callbackr   r   r   r   r   r   r<   r   r   r   reader_workerr   writer_workerprogress_barexception_in_workerread_finished	read_itemr   rM   processed_framer{   r   r   s   `  `                    @@r&   process_videor     s?   P **k*BJ ! 	J##(q*5$$)  INI >C>#0 $$M$GM	{z	B =*j!(( 
 	%%!
 15*	*,002	$$(M%."U&.uk&BO%))/: ''* !%%dA%6 !!$4$8$8$8$C	$,! -	  r*r* ".)) /y=*~ !!#NN>
 ;;G A ! *-'   	 ! !,557! 	!#!%%dA%6  	
 !!$4$8$8$8$C	$,! -
 ! !,557! 	!  r*r* ".)) /y=* =*s   AJ3H;+G&H(G&;J3?G5;J3	G#GHG##H&	G2/J31G22J35HJ3HJ3J0H,+J0,	H8	5J07H8	8J0?IJ0I3	.J02I3	3=J00J33J=c                  <    e Zd ZdZdddZed	d       Zd
dZd
dZy)
FPSMonitorzN
    A class for monitoring frames per second (FPS) to benchmark latency.
    c                &    t        |      | _        y)a  
        Args:
            sample_size: The maximum number of observations for latency
                benchmarking.

        Examples:
            ```python
            import supervision as sv

            frames_generator = sv.get_video_frames_generator(
                source_path="<SOURCE_FILE_PATH>")
            fps_monitor = sv.FPSMonitor()

            for frame in frames_generator:
                # your processing code here
                fps_monitor.tick()
                fps = fps_monitor.fps
            ```
        )maxlenN)r   all_timestamps)r,   sample_sizes     r&   r@   zFPSMonitor.__init__  s    ( -2,Er(   c                    | j                   sy| j                   d   | j                   d   z
  }|dk7  rt        | j                         |z  S dS )z
        Computes and returns the average FPS based on the stored time stamps.

        Returns:
            The average FPS. Returns 0.0 if no time stamps are stored.
        g        r   )r   len)r,   
taken_times     r&   r   zFPSMonitor.fps  sQ     ""((,t/B/B1/EE
:D/D''(J6RsRr(   c                ^    | j                   j                  t        j                                y)zI
        Adds a new time stamp to the deque for FPS calculation.
        N)r   appendtime	monotonicr+   s    r&   tickzFPSMonitor.tick  s     	""4>>#34r(   c                8    | j                   j                          y)z<
        Clears all the time stamps from the deque.
        N)r   clearr+   s    r&   resetzFPSMonitor.reset  s     	!!#r(   N)   )r   r   )r/   r   r   )	r0   r1   r2   r3   r@   r6   r   r   r   r7   r(   r&   r   r     s-    F, 
S 
S5$r(   r   )ru   r.   r$   r.   r/   rT   )F)
ru   r.   r   r   r   r   r   boolr/   z!tuple[cv2.VideoCapture, int, int])rW   r   NF)ru   r.   r   r   r   r   r   r   r   r   r/   z,Generator[npt.NDArray[np.uint8], None, None])ru   r.   r;   r.   r   z=Callable[[npt.NDArray[np.uint8], int], npt.NDArray[np.uint8]]r   r   r   r   r   r   r   r   r   r.   r   r   r/   rT   )'
__future__r   rf   rb   rl   rd   r   r   collectionsr   collections.abcr   r   dataclassesr   queuer   r	   r
   typingr   r   numpynpnumpy.typingnpt	tqdm.autor   supervision.utils.loggerr   r0   rF   r   r9   r|   r   r   r   r   r7   r(   r&   <module>r      s   " 	       / ! $ $  
    0	X	 /' /' /'d=$ =$@@ H KP '1CG&4  111 1 
	1
 1 21r ". mHmHmH LmH
 mH mH mH mH mH mH 
mH`2$ 2$r(   