o
    oi                     @  s  d Z ddlmZ dZdZedd edD ZddlZdd	l	m
Z
mZmZmZ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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ZddlZddlZdd
lm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)Z*ddl+Z*e,e*j-dse*j-e*j-_.g dZ/ej0re(j1Z2e(j3Z4e&j5eef Z6e&j7e Z8ne9dZ2e9dZ4e9dZ6e9dZ8dZ:e9dZ;ej<e=ej>f Z?G dd dZ@e@ ZAdddZBdddZCdd!d"ZDdd%d&ZE	ddd,d-ZFdd0d1ZGdd4d5ZHdd7d8ZIdd:d;ZJdd=d>ZKddAdBZLddCdDZMddFdGZNddIdJZOddLdMZPe&jQfddOdPZRddQdRZS	Sde&jQdTddUdVZT	W	Xde&jQdTddZd[ZUe&jVg d\g d]g d^ge&jQdTZWe&jXYeWZZe&jVg d_e&jQdTZ[ddadbZ\ddddeZ]e&jVg dfg dgg dhge&jQdT^ Z_e&jXYe_Z`e&jVg die&jQdTZaddjdkZbddmdnZcdd drdsZdddtduZeddxdyZfdd{d|Zgdd~dZhejidddZjejidddZkG dd dZlddddddZm	dd	ddZnddddd
ddZodddddZp	ddddZqddddddddZrdddZsdddddZt	dddddddddddddddddZudddZvdddZwdddZxG ddĄ dejyZzdddƄZ{G ddȄ dȃZ|G ddʄ de|Z}G dd̄ de|Z~G dd΄ de(je ZdddЄZddd҄ZddԜdddքZddd؄Zdddddٜddd݄Zddddd߄Z	ddddddddddddddddZdS (  a+	  `mediapy`: Read/write/show images and videos in an IPython/Jupyter notebook.

[**[GitHub source]**](https://github.com/google/mediapy) &nbsp;
[**[API docs]**](https://google.github.io/mediapy/) &nbsp;
[**[PyPI package]**](https://pypi.org/project/mediapy/) &nbsp;
[**[Colab
example]**](https://colab.research.google.com/github/google/mediapy/blob/main/mediapy_examples.ipynb)

See the [example
notebook](https://github.com/google/mediapy/blob/main/mediapy_examples.ipynb),
or better yet, [**open it in
Colab**](https://colab.research.google.com/github/google/mediapy/blob/main/mediapy_examples.ipynb).

## Image examples

Display an image (2D or 3D `numpy` array):
```python
checkerboard = np.kron([[0, 1] * 16, [1, 0] * 16] * 16, np.ones((4, 4)))
show_image(checkerboard)
```

Read and display an image (either local or from the Web):
```python
IMAGE = 'https://github.com/hhoppe/data/raw/main/image.png'
show_image(read_image(IMAGE))
```

Read and display an image from a local file:
```python
!wget -q -O /tmp/burano.png {IMAGE}
show_image(read_image('/tmp/burano.png'))
```

Show titled images side-by-side:
```python
images = {
    'original': checkerboard,
    'darkened': checkerboard * 0.7,
    'random': np.random.rand(32, 32, 3),
}
show_images(images, vmin=0.0, vmax=1.0, border=True, height=64)
```

## Video examples

Display a video (an iterable of images, e.g., a 3D or 4D array):
```python
video = moving_circle((100, 100), num_images=10)
show_video(video, fps=10)
```

Show the video frames side-by-side:
```python
show_images(video, columns=6, border=True, height=64)
```

Show the frames with their indices:
```python
show_images({f'{i}': image for i, image in enumerate(video)}, width=32)
```

Read and display a video (either local or from the Web):
```python
VIDEO = 'https://github.com/hhoppe/data/raw/main/video.mp4'
show_video(read_video(VIDEO))
```

Create and display a looping two-frame GIF video:
```python
image1 = resize_image(np.random.rand(10, 10, 3), (50, 50))
show_video([image1, image1 * 0.8], fps=2, codec='gif')
```

Darken a video frame-by-frame:
```python
output_path = '/tmp/out.mp4'
with VideoReader(VIDEO) as r:
  darken_image = lambda image: to_float01(image) * 0.5
  with VideoWriter(output_path, shape=r.shape, fps=r.fps, bps=r.bps) as w:
    for image in r:
      w.add_image(darken_image(image))
```
    )annotationsgooglez1.1.6c                 c  s    | ]}t |V  qd S N)int).0num r   D/home/ubuntu/.local/lib/python3.10/site-packages/mediapy/__init__.py	<genexpr>g       r
   .N)CallableIterableIteratorMappingSequence)Any
Resampling)
show_imageshow_images
show_videoshow_videos
read_imagewrite_image
read_videowrite_videoVideoReaderVideoWriterVideoMetadatacompress_imagedecompress_imagecompress_videodecompress_videohtml_from_compressed_imagehtml_from_compressed_videoresize_imageresize_videoto_rgbto_type
to_float01to_uint8set_output_heightset_max_output_height
color_rampmoving_circleset_show_save_dir
set_ffmpegvideo_is_available
_ArrayLike
_DTypeLike_NDArray_DTypei -1_Tc                   @  s&   e Zd ZU dZded< dZded< dS )_Configffmpeg_Pathffmpeg_name_or_pathN_Path | Noneshow_save_dir)__name__
__module____qualname__r:   __annotations__r<   r   r   r   r	   r7      s   
 r7   pathr9   argsr   kwargsreturnc                 O  s   t | g|R i |S )z9Opens the file; this is a hook for the built-in `open()`.)open)rA   rB   rC   r   r   r	   _open   s   rF   boolc                 C  s   ~ dS )zEReturns True if the path is in the filesystem accessible by `ffmpeg`.Tr   rA   r   r   r	   _path_is_local   s   rI   
str | Nonec                  C  s   t tj } rt| S dS )z;Returns a path to the ffmpeg program, or None if not found.N)shutilwhich_configr:   str)filenamer   r   r	   _search_for_ffmpeg_path   s   rP   rN   Nonec                  O  s(   i t tjdd|}t| i | dS )z'Prints arguments to stderr immediately.T)fileflushN)dictsysstderrprint)rB   rC   r   r   r	   
_print_err   s   rX   iterableIterable[_T]n
int | NoneIterator[tuple[_T, ...]]c                 C  s"   ddd}t t||t | d	S )zGReturns elements collected as tuples of length at most `n` if not None.r[   r   rY   rZ   rD   tuple[_T, ...]c                 S  s   t t|| S r   )tuple	itertoolsislice)r[   rY   r   r   r	   take      z_chunked.<locals>.taker   N)r[   r   rY   rZ   rD   r^   )iter	functoolspartial)rY   r[   rb   r   r   r	   _chunked   s   
rg   iteratortuple[_T, Iterable[_T]]c                 C  s   t | \}}t|}||fS )a  Given an iterator, returns first element and re-initialized iterator.

  >>> first_image, images = _peek_first(moving_circle())

  Args:
    iterator: An input iterator or iterable.

  Returns:
    A tuple (first_element, iterator_reinitialized) containing:
      first_element: The first element of the input.
      iterator_reinitialized: A clone of the original iterator/iterable.
  )r`   teenext)rh   peekeriterator_reinitializedfirstr   r   r	   _peek_first   s   ro   shapetuple[int, int]c                 C  sB   t | dkrtd|  dtdd | D std|  ddS )zEChecks that `shape` is of the form (height, width) with two integers.   zShape z$ is not of the form (height, width).c                 s  s    | ]	}t |tjV  qd S r   )
isinstancenumbersIntegralr   ir   r   r	   r
          z"_check_2d_shape.<locals>.<genexpr>z contains non-integers.N)len
ValueErrorallrp   r   r   r	   _check_2d_shape   s
   r}   str | Sequence[str]c                 C  sT   t j| t| tt jt jddd}t|jddd |jr(t	d|j
 d|j dd	S )
aG  Executes command, printing output from stdout and stderr.

  Args:
    args: Command to execute, which can be either a string or a sequence of word
      strings, as in `subprocess.run()`.  If `args` is a string, the shell is
      invoked to interpret it.

  Raises:
    RuntimeError: If the command's exit code is nonzero.
  FT)shellstdoutrV   checkuniversal_newlines )endrS   z	Command 'z' failed with code r   N)
subprocessrunrs   rN   PIPESTDOUTrW   r   
returncodeRuntimeErrorrB   )rB   procr   r   r	   _run  s   r   textc                C  s   t jt j|  dS )z/In a Jupyter notebook, display the HTML `text`.N)IPythondisplayHTML)r   r   r   r	   _display_html  s   r   name_or_pathc                 C  s
   | t _dS )ao  Specifies the name or path for the `ffmpeg` external program.

  The `ffmpeg` program is required for compressing and decompressing video.
  (It is used in `read_video`, `write_video`, `show_video`, `show_videos`,
  etc.)

  Args:
    name_or_path: Either a filename within a directory of `os.environ['PATH']`
      or a filepath.  The default setting is 'ffmpeg'.
  N)rM   r:   )r   r   r   r	   r0   "  s   
r0   
num_pixelsr   c              	   C  @   zt d}d|  d}|| W dS  ttfy   Y dS w )z@Overrides the height of the current output cell, if using Colab.google.colab.outputz%google.colab.output.setIframeHeight("zpx")N	importlibimport_moduleeval_jsModuleNotFoundErrorAttributeErrorr   outputsr   r   r	   r+   0  s   
r+   c              	   C  r   )zCSets the maximum height of the current output cell, if using Colab.r   z9google.colab.output.setIframeHeight(0, true, {maxHeight: z})Nr   r   r   r   r	   r,   ;  s   
r,   dtypec                 C  s2   t | } t| jt jt jfstd|  d| S )z"Returns validated media data type.Type z0 is not a valid media data type (uint or float).)npr   
issubclasstypeunsignedintegerfloatingrz   r   r   r   r	   _as_valid_media_typeL  s   

r   xc                 C  s<   t | }|jtkr|t jt t jj }t|j |S )zGConverts to ndarray (if not already), and checks validity of data type.)	r   asarrayr   rG   astypeuint8iinfomaxr   )r   ar   r   r	   _as_valid_media_arrayV  s
   


r   arrayc           	      C  s  t | }t |}~ |jtkrt|j |jtkr3||}t |t jr1||t 	|j
 }|S |j|kr<|}|S t |t jrt |jt jrSt 	|jj
}n	t |dd}d}t 	|j
}|t 	t jj
krt j|| t jd}|| d |}|S |t 	t jj
kr|t j||  d |}|S |t j||  d }t |}|t |k}||}|||< |jdkr|n|d }|S t |t jsJ ||}t |jt jr||t 	|jj
 }|S )aG  Returns media array converted to specified type.

  A "media array" is one in which the dtype is either a floating-point type
  (np.float32 or np.float64) or an unsigned integer type.  The array values are
  assumed to lie in the range [0.0, 1.0] for floating-point values, and in the
  full range for unsigned integers, e.g. [0, 255] for np.uint8.

  Conversion between integers and floats maps uint(0) to 0.0 and uint(MAX) to
  1.0.  The input array may also be of type bool, whereby True maps to
  uint(MAX) or 1.0.  The values are scaled and clamped as appropriate during
  type conversions.

  Args:
    array: Input array-like object (floating-point, unsigned int, or bool).
    dtype: Desired output type (floating-point or unsigned int).

  Returns:
    Array `a` if it is already of the specified dtype, else a converted array.
                ?r         ?r   )r   r   r   rG   r   r   
issubdtyper   r   r   r   clipuint16r   float32uint32float64
atleast_1dndimr   )	r   r   r   resultsrc_maxdst_maxscaledstvalues_too_larger   r   r	   r(   _  sL   









r(   r   c                 C  sP   t | } t |}t |t jstd| dt | jt jr#| S t| |S )a  If array has unsigned integers, rescales them to the range [0.0, 1.0].

  Scaling is such that uint(0) maps to 0.0 and uint(MAX) maps to 1.0.  See
  `to_type`.

  Args:
    a: Input array.
    dtype: Desired floating-point type if rescaling occurs.

  Returns:
    A new array of dtype values in the range [0.0, 1.0] if the input array `a`
    contains unsigned integers; otherwise, array `a` is returned unchanged.
  r   z is not floating-point.)r   r   r   r   r   rz   r(   )r   r   r   r   r	   r)     s   


r)   c                 C  s   t | tjS )z7Returns array converted to uint8 values; see `to_type`.)r(   r   r   )r   r   r   r	   r*     s   r*   @   r   r   c                C  sH   t |  t|}tt| ddd |  }tj|dddd}t||S )a/  Returns an image of a red-green color gradient.

  This is useful for quick experimentation and testing.  See also
  `moving_circle` to generate a sample video.

  Args:
    shape: 2D spatial dimensions (height, width) of generated image.
    dtype: Type (uint or floating) of resulting pixel values.
  r   r   rr   r   axis)r}   r   r   moveaxisindicesinsertr(   )rp   r   yximager   r   r	   r-     s
   
r-      r   
   
num_imagesc                  s@   t  t  d
 fddtfddtD S )a  Returns a video of a circle moving in front of a color ramp.

  This is useful for quick experimentation and testing.  See also `color_ramp`
  to generate a sample image.

  >>> show_video(moving_circle((480, 640), 60), fps=60)

  Args:
    shape: 2D spatial dimensions (height, width) of generated video.
    num_images: Number of video frames.
    dtype: Type (uint or floating) of resulting pixel values.
  image_indexr   rD   r4   c                   s   t  d}ttdd}d d d | d   f}td d }tj|| d dd	|k }d
}t tjrFt|g d }|||< |S )zReturns a video frame image.r   r   r   g333333?   r   g?rr   r   )r   r   r   )	r-   r   r   r   minsumr   r   r(   )r   r   r   centerradius_squaredinsidewhite_circle_color)r   r   rp   r   r	   generate_image  s    z%moving_circle.<locals>.generate_imagec                      g | ]} |qS r   r   rv   )r   r   r	   
<listcomp>      z!moving_circle.<locals>.<listcomp>N)r   r   rD   r4   )r}   r   r   r   range)rp   r   r   r   )r   r   r   rp   r	   r.     s   
r.   )gA`"?gxÅ¿g>?)gbX9?gx|ҿgb!z)gv/?g}?gE)r   r   r   rgbc                 C  s4   t | } | jd dkrtd| j d| t t S )zReturns the RGB image/video mapped to YUV [0,1] color space.

  Note that the "YUV" color space used by video compressors is actually YCbCr!

  Args:
    rgb: Input image in sRGB space.
  r      The last dimension in 
 is not 3.)r)   rp   rz   _YUV_FROM_RGB_MATRIX_YUV_CHROMA_OFFSETr   r   r   r	   yuv_from_rgb  s   r   yuvc                 C  s4   t | } | jd dkrtd| j d| t t S )z<Returns the YUV image/video mapped to RGB [0,1] color space.r   r   r   r   )r)   rp   rz   r   _RGB_FROM_YUV_MATRIX)r   r   r   r	   rgb_from_yuv  s   r   )gX9^P@gV-`@gK8@)gtBgER      \@)r   gMrWgX962)g      0@      `@r   c                 C  s8   t | } | jd dkrtd| j d| t t d S )zReturns the RGB image/video mapped to YCbCr [0,1] color space.

  The YCbCr color space is the one called "YUV" by video compressors.

  Args:
    rgb: Input image in sRGB space.
  r   r   r   r        o@)r)   rp   rz   _YCBCR_FROM_RGB_MATRIX_YCBCR_OFFSETr   r   r   r	   ycbcr_from_rgb+  s   r   ycbcrc                 C  s8   t | } | jd dkrtd| j d| d t t S )z>Returns the YCbCr image/video mapped to RGB [0,1] color space.r   r   r   r   r   )r)   rp   rz   r   _RGB_FROM_YCBCR_MATRIX)r   r   r   r	   rgb_from_ycbcr9  s   r   r   modePIL.Image.Imagec                 C  s4   t | } | jdvrtd| j dtjj| |dS )zGReturns a PIL image given a numpy matrix (either uint8 or float [0,1]).rr   r   Image shape  is neither 2D nor 3D.r   )r   r   rz   rp   PILImage	fromarray)r   r   r   r   r	   
_pil_imageD  s   
r   c                   s   t | } | jdvrtd| j dt  t| jtjp#| jtj	ko(| jdk}| jtj	ko:| jdko:| jd dv }|s?|rVtj
t| j ddd tjjjd	| jd
S | jdkrfttt|  | jS t fddt| ddD S )a+  Resizes image to specified spatial dimensions using a Lanczos filter.

  Args:
    image: Array-like 2D or 3D object, where dtype is uint or floating-point.
    shape: 2D spatial dimensions (height, width) of output image.

  Returns:
    A resampled image whose spatial dimensions match `shape`.
  r   r   r   rr   r   )r      Nr   )resampler   c                      g | ]}t | qS r   r%   )r   channelr|   r   r	   r   o      z resize_image.<locals>.<listcomp>r   )r   r   rz   rp   r}   r   r   r   r   r   r   r   resizer   r   r   LANCZOSr(   r%   r)   dstackr   )r   rp   supported_single_channelsupported_multichannelr   r|   r	   r%   L  s,   

"
r%   videoIterable[_NDArray]c                   s    t   t fdd| D S )zResizes `video` to specified spatial dimensions using a Lanczos filter.

  Args:
    video: Iterable of images.
    shape: 2D spatial dimensions (height, width) of output video.

  Returns:
    A resampled video whose spatial dimensions match `shape`.
  c                   r   r   r   r   r   r|   r   r	   r     r   z resize_video.<locals>.<listcomp>)r}   r   r   )r  rp   r   r|   r	   r&   v  s   
r&   path_or_urlc                 C  s   t | to	| dS )N)zhttp://zhttps://zfile://)rs   rN   
startswith)r	  r   r   r	   _is_url  s   r  bytesc                 C  s   t | r(t| tsJ tj| }| }W d   |S 1 s!w   Y  |S t| d}| }W d   |S 1 s=w   Y  |S )zCReturns the contents of the file specified by either a path or URL.Nrb)r  rs   rN   urllibrequesturlopenreadrF   )r	  responsedatafr   r   r	   read_contents  s   



r  Iterator[str]c                 c  s    t | s	t| s<t| j}t }t|d|  }|t|  t	|V  W d   dS 1 s5w   Y  dS t	| V  dS )zContext to copy a remote file locally to read from it.

  Args:
    path_or_url: File, which may be remote.

  Yields:
    The name of a local file which may be a copy of a remote file.
  rR   N)
r  rI   pathlibPathsuffixtempfileTemporaryDirectorywrite_bytesr  rN   )r	  r  directory_nametmp_pathr   r   r	   _read_via_local_file  s   

"r  c              	   c  s    t | rt| V  dS t| j}t =}t|d|  }t|V  t| dd}||	  W d   n1 s>w   Y  W d   dS W d   dS 1 sVw   Y  dS )zContext to write a temporary local file and subsequently copy it remotely.

  Args:
    path: File, which may be remote.

  Yields:
    The name of a local file which may be subsequently copied remotely.
  rR   wbr   N)
rI   rN   r  r  r  r  r  rF   write
read_bytes)rA   r  r  r  r  r   r   r	   _write_via_local_file  s   


"r#  c                   @  s.   e Zd ZdZdddZddd	ZdddZdS )r/   a  Save all titled output from `show_*()` calls into files.

  If the specified `directory` is not None, all titled images and videos
  displayed by `show_image`, `show_images`, `show_video`, and `show_videos` are
  also saved as files within the directory.

  It can be used either to set the state or as a context manager:

  >>> set_show_save_dir('/tmp')
  >>> show_image(color_ramp(), title='image1')  # Creates /tmp/image1.png.
  >>> show_video(moving_circle(), title='video2')  # Creates /tmp/video2.mp4.
  >>> set_show_save_dir(None)

  >>> with set_show_save_dir('/tmp'):
  ...   show_image(color_ramp(), title='image1')  # Creates /tmp/image1.png.
  ...   show_video(moving_circle(), title='video2')  # Creates /tmp/video2.mp4.
  	directoryr;   c                 C  s   t j| _|t _d S r   )rM   r<   _old_show_save_dir)selfr$  r   r   r	   __init__  s   
zset_show_save_dir.__init__rD   rQ   c                 C  s   d S r   r   r&  r   r   r	   	__enter__  s   zset_show_save_dir.__enter___r   c                 G  s   | j t_d S r   )r%  rM   r<   r&  r*  r   r   r	   __exit__     zset_show_save_dir.__exit__N)r$  r;   rD   rQ   r*  r   rD   rQ   )r=   r>   r?   __doc__r'  r)  r,  r   r   r   r	   r/     s
    

r/   T)apply_exif_transposer   r1  c                C  s   t | }t|||S )a  Returns an image read from a file path or URL.

  Decoding is performed using `PIL`, which supports `uint8` images with 1, 3,
  or 4 channels and `uint16` images with a single channel.

  Args:
    path_or_url: Path of input file.
    apply_exif_transpose: If True, rotate image according to EXIF orientation.
    dtype: Data type of the returned array.  If None, `np.uint8` or `np.uint16`
      is inferred automatically.
  )r  r    )r	  r1  r   r  r   r   r	   r     s   r   pngfmtc                 K  sj   t |}t|jtjrt|}t| d}t|j|fd|i| W d   dS 1 s.w   Y  dS )aY  Writes an image to a file.

  Encoding is performed using `PIL`, which supports `uint8` images with 1, 3,
  or 4 channels and `uint16` images with a single channel.

  File format is explicitly provided by `fmt` and not inferred by `path`.

  Args:
    path: Path of output file.
    image: Array-like object.  If its type is float, it is converted to np.uint8
      using `to_uint8` (thus clamping to the input to the range [0.0, 1.0]).
      Otherwise it must be np.uint8 or np.uint16.
    fmt: Desired compression encoding, e.g. 'png'.
    **kwargs: Additional parameters for `PIL.Image.save()`.
  r   formatN)	r   r   r   r   r   r*   rF   r   save)rA   r   r3  rC   r  r   r   r	   r     s   "r   grayvminvmaxcmapr8  float | Noner9  r:  &str | Callable[[_ArrayLike], _NDArray]c                C  s   t | }~ |du rttt||tjn|}|du r,ttt||tj n|}|d| || tt	j
  }t|trWttdrOtj| }n
tjj|}n|}||}|jd dkrwtt|d dkrw|ddd	f }|S )
a7  Maps scalar values to RGB using value bounds and a color map.

  Args:
    array: Scalar values, with arbitrary shape.
    vmin: Explicit min value for remapping; if None, it is obtained as the
      minimum finite value of `array`.
    vmax: Explicit max value for remapping; if None, it is obtained as the
      maximum finite value of `array`.
    cmap: A `pyplot` color map or callable, to map from 1D value to 3D or 4D
      color.

  Returns:
    A new array in which each element is affinely mapped from [vmin, vmax]
    to [0.0, 1.0] and then color-mapped.
  Nfloat	colormapsr   r   ).r   r   .r   )r   r   aminwhereisfiniteinfamaxr   finfor=  epsrs   rN   hasattr
matplotlibr>  pyplotcmget_cmaprp   r{   r)   )r   r8  r9  r:  r   rgb_from_scalarr   r   r	   r'     s   (*"

$r'   )r3  c                K  sV   t | } t }t| j|fd|i| | W  d   S 1 s$w   Y  dS )a  Returns a buffer containing a compressed image.

  Args:
    image: Array in a format supported by `PIL`, e.g. np.uint8 or np.uint16.
    fmt: Desired compression encoding, e.g. 'png'.
    **kwargs: Options for `PIL.save()`, e.g. `optimize=True` for greater
      compression.
  r4  N)r   ioBytesIOr   r5  getvalue)r   r3  rC   r   r   r   r	   r   >  s
   
$r   r  c                 C  sN   t jt| }|rt j|}|du r |jdkrtj	ntj
}tj||dS )a  Returns an image from a compressed data buffer.

  Decoding is performed using `PIL`, which supports `uint8` images with 1, 3,
  or 4 channels and `uint16` images with a single channel.

  Args:
    data: Buffer containing compressed image.
    dtype: Data type of the returned array.  If None, `np.uint8` or `np.uint16`
      is inferred automatically.
    apply_exif_transpose: If True, rotate image according to EXIF orientation.
  NIr   )r   r   rE   rL  rM  ImageOpsexif_transposer   r   r   r   r   )r  r   r1  	pil_imager   r   r	   r    O  s   r    F)titleborder	pixelatedr3  widthheightrS  rT  
bool | strrU  c          
      C  s   t | d}t|tr| d}n|rd}nd}|rdnd}d| d| d	| d
| d| d| d}	|r@d| d|	 d}	|	S )a  Returns an HTML string with an image tag containing encoded data.

  Args:
    data: Compressed image bytes.
    width: Width of HTML image in pixels.
    height: Height of HTML image in pixels.
    title: Optional text shown centered above image.
    border: If `bool`, whether to place a black boundary around the image, or if
      `str`, the boundary CSS style.
    pixelated: If True, sets the CSS style to 'image-rendering: pixelated;'.
    fmt: Compression encoding.
  utf-8; border:1px solid black; r   rU  autoz<img width="
" height="	" style="zimage-rendering:z%; object-fit:cover;" src="data:image/z;base64,z"/><div style="display:flex; align-items:left;">
      <div style="display:flex; flex-direction:column; align-items:center;">
      <div></div><div></div></div></div>base64	b64encodedecoders   rN   )
r  rV  rW  rS  rT  rU  r3  b64s_pixelatedr   r   r   r	   r#   e  s0   
r#   c                 C  s   t |dks
J || r|r| |fS | r&|s&| t| |d |d   d fS |r:| s:t||d |d   d |fS |ddd S )zBReturns (width, height) given optional parameters and image shape.rr   r   r   r   Nr   )ry   r   )rV  rW  rp   r   r   r	   _get_width_height  s     rh  )rS  c                K  s   t t| g|gfi |S )a  Displays an image in the notebook and optionally saves it to a file.

  See `show_images`.

  >>> show_image(np.random.rand(100, 100))
  >>> show_image(np.random.randint(0, 256, size=(80, 80, 3), dtype='uint8'))
  >>> show_image(np.random.rand(10, 10) - 0.5, cmap='bwr', height=100)
  >>> show_image(read_image('/tmp/image.png'))
  >>> url = 'https://github.com/hhoppe/data/raw/main/image.png'
  >>> show_image(read_image(url))

  Args:
    image: 2D array-like, or 3D array-like with 1, 3, or 4 channels.
    title: Optional text shown centered above the image.
    **kwargs: See `show_images`.

  Returns:
    html string if `return_html` is `True`.
  )r   r   r   )r   rS  rC   r   r   r	   r     s   r   r   r   )rV  rW  
downsamplecolumnsr8  r9  r:  rT  ylabel
html_classrU  return_htmlimages/Iterable[_ArrayLike] | Mapping[str, _ArrayLike]titlesIterable[str | None] | Noneri  rj  rk  rl  bool | Nonerm  c                  s  t | tr|durtdt|  t|  n*t| |du r*dgt nt|ttkrEtdt dt ddfd
dfddD dfdd|rjfddD dd D 
t
D ]/\}}|rtj	rt
tj	| d }t|dd}|| W d   n1 sw   Y  qvd 	
f
dd}| }t|td krdd D dd D 
| }t|td ks|r|S t| dS )a  Displays a row of images in the IPython/Jupyter notebook.

  If a directory has been specified using `set_show_save_dir`, also saves each
  titled image to a file in that directory based on its title.

  >>> image1, image2 = np.random.rand(64, 64, 3), color_ramp((64, 64))
  >>> show_images([image1, image2])
  >>> show_images({'random image': image1, 'color ramp': image2}, height=128)
  >>> show_images([image1, image2] * 5, columns=4, border=True)

  Args:
    images: Iterable of images, or dictionary of `{title: image}`.  Each image
      must be either a 2D array or a 3D array with 1, 3, or 4 channels.
    titles: Optional strings shown above the corresponding images.
    width: Optional, overrides displayed width (in pixels).
    height: Optional, overrides displayed height (in pixels).
    downsample: If True, each image whose width or height is greater than the
      specified `width` or `height` is resampled to the display resolution. This
      improves antialiasing and reduces the size of the notebook.
    columns: Optional, maximum number of images per row.
    vmin: For single-channel image, explicit min value for display.
    vmax: For single-channel image, explicit max value for display.
    cmap: For single-channel image, `pyplot` color map or callable to map 1D to
      3D color.
    border: If `bool`, whether to place a black boundary around the image, or if
      `str`, the boundary CSS style.
    ylabel: Text (rotated by 90 degrees) shown on the left of each row.
    html_class: CSS class name used in definition of HTML element.
    pixelated: If True, sets the CSS style to 'image-rendering: pixelated;'; if
      False, sets 'image-rendering: auto'; if None, uses pixelated rendering
      only on images for which `width` or `height` introduces magnification.
    return_html: If `True` return the raw HTML `str` instead of displaying.

  Returns:
    html string if `return_html` is `True`.
  Nz3Cannot have images dictionary and titles parameter.z2Number of images does not match number of titles ( vs ).r   r2   rD   r4   c                   s   t | } | jdks| jdkr| jd dv std| j d| jdkr5| jd dkr5| d d d d df } | jdkrBt|  d} | S )	Nrr   r   )r   r   r   zImage with shape z? is neither a 2D array nor a 3D array with 1, 3, or 4 channels.r   r   r7  )r   r   rp   rz   r'   )r   )r:  r9  r8  r   r	   ensure_mapped_to_rgb  s   "
z)show_images.<locals>.ensure_mapped_to_rgbc                   r   r   r   r  )ru  r   r	   r     r   zshow_images.<locals>.<listcomp>c                   sH   | j d d }t |\}}||d k s||d k r"t| ||f} | S )Nrr   r   r   )rp   rh  r%   )r   rp   wh)rW  rV  r   r	   maybe_downsample	  s
   z%show_images.<locals>.maybe_downsamplec                   r   r   r   r  )rx  r   r	   r     r   c                 S     g | ]}t t|qS r   r   r*   r  r   r   r	   r         z.pngr   r   rN   c                    s   g } t D ]5\}}}t	|jd d \}}||jd kp'||jd k}d ur.n|}| t|||||d qg }t| D ]-}	d d fdd|	D }

rfd	}  d
| d
 d|
 }
|d d|
 d qEd|S )Nrr   r   r   )rS  rT  rU  <td style="padding:1px;">r   c                 3      | ]
}  | d V  qdS z</td>Nr   r   etdr   r	   r
   )      zCshow_images.<locals>.html_from_compressed_images.<locals>.<genexpr>3writing-mode:vertical-lr; transform:rotate(180deg);<span style=""></span></td><table class=""" style="border-spacing:0px;"><tr></tr></table>)ziprh  rp   appendr#   rg   join)html_stringsr   rS  png_datarv  rw  	magnified
pixelated2table_stringsrow_html_stringsr   style)
rT  rj  rW  rl  list_imageslist_titlesrU  	png_datasrV  rk  r  r	   html_from_compressed_images  s.   
z0show_images.<locals>.html_from_compressed_imagesr   c                 S  s$   g | ]}|d d dd d df qS )Nrr   r   r  r   r   r	   r   5  s   $ c                 S  ry  r   rz  r  r   r   r	   r   6  r{  )r   r2   rD   r4   )r   r4   rD   r4   rD   rN   )rs   r   rz   listkeysvaluesry   r  rM   r<   r  r  rF   r!  _IPYTHON_HTML_SIZE_LIMITr   )rn  rp  rV  rW  ri  rj  r8  r9  r:  rT  rk  rl  rU  rm  rS  r  rA   r  r  r   r   )rT  r:  rj  ru  rW  rl  r  r  rx  rU  r  r9  r8  rV  rk  r	   r     sL   
5
 codecc                 C  s   | dkrdS dS )Ngif.gifz.mp4r   r  r   r   r	   _filename_suffix_from_codecA  rc   r  c                  C  s    t  } | stdtj d| S )Nz	Program 'zB' is not found; perhaps install ffmpeg using 'apt install ffmpeg'.)rP   r   rM   r:   rH   r   r   r	   _get_ffmpeg_pathE  s   r  c                   C  s
   t  duS )zKReturns True if the program `ffmpeg` is found.

  See also `set_ffmpeg`.
  N)rP   r   r   r   r	   r1   O  s   
r1   c                   @  s2   e Zd ZU dZded< ded< ded< ded	< d
S )r   a  Represents the data stored in a video container header.

  Attributes:
    num_images: Number of frames that is expected from the video stream.  This
      is estimated from the framerate and the duration stored in the video
      header, so it might be inexact.
    shape: The dimensions (height, width) of each video frame.
    fps: The framerate in frames per second.
    bps: The estimated bitrate of the video stream in bits per second, retrieved
      from the video header.
  r   r   rq   rp   r=  fpsr\   bpsN)r=   r>   r?   r0  r@   r   r   r   r	   r   W  s   
 r   c                 C  s  t |  std|  dt ddt| dddddd	d
g}tj|tjdd}|	 \}}W d   n1 s9w   Y  d } } }}|
dD ]l}	td|	 }
r^t|
dd }td|	 }rlt|d }d|	v rd|	v rtd|	 }
std|	 t|
dt|
d}}td|	 }
std|	 t|
d}td|	 }
rt|
d}qK|std| |std| |dv r||}}||f}t||||S )z?Returns attributes of video stored in the specified local file.zVideo file 'z' is not found.-nostdin-iz-acodeccopy-vcodec-fnull-rY  )rV   encodingN
z, bitrate: *([0-9.]+) kb/sr   i  zframe= *([0-9]+) r   z
Stream #0:z: Video:z, ([0-9]+)x([0-9]+)z)Unable to parse video dimensions in line rr   z, ([0-9.]+) fpsz(Unable to parse video framerate in line z\s*rotate\s*:\s*(\d+)z Unable to find frames in video: zUnable to parse video header: )Z   i  )r  r  is_filer   r  rN   r   Popenr   communicatesplitresearchr   groupfindallr=  	fullmatchr   )rA   commandr   r*  errr  r   rV  rotationlinematchmatchesrW  r  rp   r   r   r	   _get_video_metadataj  sX   
r  c                   @  s   e Zd ZdZd
ddZd	S )_VideoIOz/Base class for `VideoReader` and `VideoWriter`.r   r5   image_formatrN   rD   c                 C  sF   dddt j }tjddddtjd| d	| d
| di|j | S )z8Returns ffmpeg pix_fmt given data type and image format.lebe)littlebigrgb24yuv444pr6  r   r   r6  rgb48	yuv444p16gray16)rU   	byteorderr   r   r   r   )r&  r   r  native_endian_suffixr   r   r	   _get_pix_fmt  s    z_VideoIO._get_pix_fmtN)r   r5   r  rN   rD   rN   )r=   r>   r?   r0  r  r   r   r   r	   r    s    r  c                   @  s   e Zd ZU dZded< ded< ded< ded	< d
ed< ded< ded< ded< d
ed< dejdd*ddZd+ddZd,dd Z	d-d"d#Z
d.d%d&Zd/d'd(Zd)S )0r   a7  Context to read a compressed video as an iterable over its images.

  >>> with VideoReader('/tmp/river.mp4') as reader:
  ...   print(f'Video has {reader.num_images} images with shape={reader.shape},'
  ...         f' at {reader.fps} frames/sec and {reader.bps} bits/sec.')
  ...   for image in reader:
  ...     print(image.shape)

  >>> with VideoReader('/tmp/river.mp4') as reader:
  ...   video = np.array(tuple(reader))

  >>> url = 'https://github.com/hhoppe/data/raw/main/video.mp4'
  >>> with VideoReader(url) as reader:
  ...   show_video(reader)

  Attributes:
    path_or_url: Location of input video.
    output_format: Format of output images (default 'rgb').  If 'rgb', each
      image has shape=(height, width, 3) with R, G, B values.  If 'yuv', each
      image has shape=(height, width, 3) with Y, U, V values.  If 'gray', each
      image has shape=(height, width).
    dtype: Data type for output images.  The default is `np.uint8`.  Use of
      `np.uint16` allows reading 10-bit or 12-bit data without precision loss.
    metadata: Object storing the information retrieved from the video header.
      Its attributes are copied as attributes in this class.
    num_images: Number of frames that is expected from the video stream.  This
      is estimated from the framerate and the duration stored in the video
      header, so it might be inexact.
    shape: The dimensions (height, width) of each video frame.
    fps: The framerate in frames per second.
    bps: The estimated bitrate of the video stream in bits per second, retrieved
      from the video header.
  r9   r	  rN   output_formatr5   r   r   metadatar   r   rq   rp   r=  r  r\   r  _num_bytes_per_imager   )r  r   r3   c                C  sj   |dvrt d| d|| _|| _t|| _| jjtjtjfvr*t d| dd | _d | _	d | _
d S )N>   r   r   r6  zOutput format  is not rgb, yuv, or gray.r    is not np.uint8 or np.uint16.)rz   r	  r  r   r   r   r   r   r  _popen_proc)r&  r	  r  r   r   r   r	   r'    s   

zVideoReader.__init__rD   'VideoReader'c                 C  s   t  }z`t| j| _| j }t|| _| j\| _| _| _| _	| 
| j| j}dddd| j }| jj}t| j| | | _|dddd|dd	d
dd|dddg}tj|tjtjd| _| j | _W | S  tyr   | d d d   w )Nr   r   r  -vpanicr  r  r  rawvideor  
image2pipe-pix_fmtz-vsyncvfrr  )r   rV   )r  r  r	  r)  r  r  r   rp   r  r  r  r   r  itemsizemathprodr  r   r  r   r  r  	Exceptionr,  )r&  ffmpeg_pathtmp_namepix_fmtnum_channelsbytes_per_channelr  r   r   r	   r)    sH   


zVideoReader.__enter__r*  r   rQ   c                 G     |    d S r   closer+  r   r   r	   r,    r-  zVideoReader.__exit___NDArray | Nonec                 C  s   | j sJ d| j jsJ | j j| j}|s|   dS t|| jks&J tj|| jd}| j	dkr@|j
g | jdR  }|S | j	dkrVt|j
dg| jR  dd}|S | j	d	krc|j
| j }|S t)
zReads a video image frame (or None if at end of file).

    Returns:
      A numpy array in the format specified by `output_format`, i.e., a 3D
      array with 3 color channels, except for format 'gray' which is 2D.
    z.Error: reading from an already closed context.Nr   r   r   r   r   rr   r6  )r  r   r  r  r  ry   r   
frombufferr   r  reshaperp   r   AssertionError)r&  r  r   r   r   r	   r    s$   


zVideoReader.readIterator[_NDArray]c                 c  s     	 |   }|d u rd S |V  qr   )r  )r&  r   r   r   r	   __iter__4  s   zVideoReader.__iter__c                 C  sF   | j r| j ddd d| _ d| _| jr!| jddd d| _dS dS )zCTerminates video reader.  (Called automatically at end of context.)N)r  r,  r  r  r(  r   r   r	   r  ;  s   
zVideoReader.closeN)r	  r9   r  rN   r   r3   )rD   r  r/  )rD   r  )rD   r  r.  )r=   r>   r?   r0  r@   r   r   r'  r)  r,  r  r  r  r   r   r   r	   r     s&   
 "

*

r   c                   @  s\   e Zd ZdZddddddddejdd
d-ddZd.d!d"Zd/d%d&Zd0d)d*Z	d1d+d,Z
dS )2r   a	  Context to write a compressed video.

  >>> shape = (480, 640)
  >>> with VideoWriter('/tmp/v.mp4', shape, fps=60) as writer:
  ...   for image in moving_circle(shape, num_images=60):
  ...     writer.add_image(image)
  >>> show_video(read_video('/tmp/v.mp4'))


  Bitrate control may be specified using at most one of: `bps`, `qp`, or `crf`.
  If none are specified, `qp` is set to a default value.
  See https://slhck.info/video/2017/03/01/rate-control.html

  If codec is 'gif', the args `bps`, `qp`, `crf`, and `encoded_format` are
  ignored.

  Attributes:
    path: Output video.  Its suffix (e.g. '.mp4') determines the video container
      format.  The suffix must be '.gif' if the codec is 'gif'.
    shape: 2D spatial dimensions (height, width) of video image frames.  The
      dimensions must be even if 'encoded_format' has subsampled chroma (e.g.,
      'yuv420p' or 'yuv420p10le').
    codec: Compression algorithm as defined by "ffmpeg -codecs" (e.g., 'h264',
      'hevc', 'vp9', or 'gif').
    metadata: Optional VideoMetadata object whose `fps` and `bps` attributes are
      used if not specified as explicit parameters.
    fps: Frames-per-second framerate (default is 60.0 except 25.0 for 'gif').
    bps: Requested average bits-per-second bitrate (default None).
    qp: Quantization parameter for video compression quality (default None).
    crf: Constant rate factor for video compression quality (default None).
    ffmpeg_args: Additional arguments for `ffmpeg` command, e.g. '-g 30' to
      introduce I-frames, or '-bf 0' to omit B-frames.
    input_format: Format of input images (default 'rgb').  If 'rgb', each image
      has shape=(height, width, 3) or (height, width).  If 'yuv', each image has
      shape=(height, width, 3) with Y, U, V values.  If 'gray', each image has
      shape=(height, width).
    dtype: Expected data type for input images (any float input images are
      converted to `dtype`).  The default is `np.uint8`.  Use of `np.uint16` is
      necessary when encoding >8 bits/channel.
    encoded_format: Pixel format as defined by `ffmpeg -pix_fmts`, e.g.,
      'yuv420p' (2x2-subsampled chroma), 'yuv444p' (full-res chroma),
      'yuv420p10le' (10-bit per channel), etc.  The default (None) selects
      'yuv420p' if all shape dimensions are even, else 'yuv444p'.
  h264Nr   r   )
r  r  r  r  qpcrfffmpeg_argsinput_formatr   encoded_formatrA   r9   rp   rq   r  rN   r  VideoMetadata | Noner  r;  r  r\   r  r  r  r~   r  r   r3   r  rJ   rD   rQ   c       
         C  s  t | |d u r|r|j}|d u r|dkrdnd}|dkr%td| d|d u r.|r.|j}|d ur6t|nd }|d urH|dkrHtd| d|d ur]t|trU|dkr]td	| d
tdd |||fD }|dkr{td| d| d| dt|	trt	|	nt
|	}	|
dvrtd|
 dt|}|jtjtjfvrtd| dt|| _|| _tdd |D }|d u r|rdnd}|s|drtd| d| d|| _|| _|| _|| _|| _|	| _|
| _|| _|| _|dkr	|	s	t| jdkrdnd}|d urd | gng |d urd!| gng  |d ur,d d"d#| gng  | _| jdkrX| jjd$krFtd%| j d&d'| _g | _d(}d)|d*dg| j | _d | _ d | _!d | _"d S )+Nr  g      9@g      N@r   zFrame-per-second value z is invalid.r   zBitrate value zQuantization parameter z is not a positive integer.c                 s  s    | ]}|d uV  qd S r   r   )r   r   r   r   r	   r
     r   z'VideoWriter.__init__.<locals>.<genexpr>r   z-Must specify at most one of bps, qp, or crf (z, rt  >   r   r   r6  zInput format r  r   r  c                 s  s    | ]	}|d  dkV  qdS )rr   r   Nr   )r   dimr   r   r	   r
     rx   yuv420pr  )yuv42yuvj42zWith encoded_format z., video dimensions must be even, but shape is r   i        z-vbz-qp0z-crfr  zFile 'z' does not have a .gif suffix.pal8z1split[s0][s1];[s0]palettegen[p];[s1][p]paletteusez-vfr  )#r}   r  rz   r  r   rs   r   rN   shlexr  r  r   r   r   r   r   r  r  rA   rp   r{   r
  r  r  r  r  r  r  r  r  _bitrate_argsr  r#  r  r  )r&  rA   rp   r  r  r  r  r  r  r  r  r   r  num_rate_specificationsall_dimensions_are_evenvideo_filterr   r   r	   r'  u  s   


zVideoWriter.__init__'VideoWriter'c                 C  s   t  }| | j| j}zMt| j| _| j }| j\}}|ddddddd|d| d| d	| j d
ddd| j	d| j
g| j | j d|g }tj|tjtjd| _| j | _W | S  tyg   | d d d   w )Nr  errorr  r  r  r  z-sr   z-rr  r  z-anz-y)stdinrV   )r  r  r   r  r#  rA   r)  rp   r  r  r  r  r  r   r  r   r  r  r  r,  )r&  r  input_pix_fmtr  rW  rV  r  r   r   r	   r)    sV   


zVideoWriter.__enter__r*  r   c                 G  r  r   r  r+  r   r   r	   r,    r-  zVideoWriter.__exit__r   r4   c                 C  s  | j sJ dt|jjtjtjfrt|| j}|j| jkr+td|j d| j d| j	dkr?|j
dkr>td|j dn'|j
dkrQ| j	d	krQt|||f}|j
d
kr]|jd d
ksftd|j d|jdd | jkrtd|jdd  d| j d| j	dkrt|dd}| }| j jsJ | j j|t|kr| j   | j jsJ | j j  }td| j d| dS )a"  Writes a video frame.

    Args:
      image: Array whose dtype and first two dimensions must match the `dtype`
        and `shape` specified in `VideoWriter` initialization.  If
        `input_format` is 'gray', the image must be 2D.  For the 'rgb'
        input_format, the image may be either 2D (interpreted as grayscale) or
        3D with three (R, G, B) channels.  For the 'yuv' input_format, the image
        must be 3D with three (Y, U, V) channels.

    Raises:
      RuntimeError: If there is an error writing to the output file.
    z,Error: writing to an already closed context.zImage type z != r   r6  rr   zImage dimensions z are not 2D.r   r   z are invalid.Nz- do not match those of the initialized video r   r   Error writing '': )r  r   r   r   r   r   bool_r(   rz   r  r   rp   r  r   tobytesr  r!  ry   waitrV   r  re  r   rA   )r&  r   r  r   r   r   r	   	add_image   s:   



zVideoWriter.add_imagec                 C  s   | j r<| jr| jjr| jjsJ | jj  | j r.| jj  }td| j	 d| | j 
ddd d| _ d| _| jrL| j
ddd d| _dS dS )zFFinishes writing the video.  (Called automatically at end of context.)r  r  N)r  r  r  rV   r  r  r  re  r   rA   r,  r#  )r&  r   r   r   r	   r  *  s   

zVideoWriter.close)rA   r9   rp   rq   r  rN   r  r  r  r;  r  r\   r  r\   r  r;  r  r~   r  rN   r   r3   r  rJ   rD   rQ   )rD   r  r/  )r   r4   rD   rQ   r.  )r=   r>   r?   r0  r   r   r'  r)  r,  r  r  r   r   r   r	   r   G  s"    2
Y
/
*r   c                   @  s2   e Zd ZU dZded< 	ddddZdddZdS )_VideoArrayzEWrapper to add a VideoMetadata `metadata` attribute to a numpy array.r  r  Nclstyping.Type['_VideoArray']input_arrayr4   rD   '_VideoArray'c                 C  s   t || }||_|S r   )r   r   viewr  )r  r  r  objr   r   r	   __new__@  s   z_VideoArray.__new__r  r   rQ   c                 C  s   |d u rd S t |dd | _d S )Nr  )getattrr  )r&  r  r   r   r	   __array_finalize__I  s   z_VideoArray.__array_finalize__r   )r  r  r  r4   r  r  rD   r  )r  r   rD   rQ   )r=   r>   r?   r0  r@   r  r  r   r   r   r	   r  ;  s   
 	r  c                 K  sL   t | fi |}ttt||jdW  d   S 1 sw   Y  dS )a$  Returns an array containing all images read from a compressed video file.

  >>> video = read_video('/tmp/river.mp4')
  >>> print(f'The framerate is {video.metadata.fps} frames/s.')
  >>> show_video(video)

  >>> url = 'https://github.com/hhoppe/data/raw/main/video.mp4'
  >>> show_video(read_video(url))

  Args:
    path_or_url: Input video file.
    **kwargs: Additional parameters for `VideoReader`.

  Returns:
    A 4D `numpy` array with dimensions (frame, height, width, channel), or a 3D
    array if `output_format` is specified as 'gray'.  The returned array has an
    attribute `metadata` containing `VideoMetadata` information.  This enables
    `show_video` to retrieve the framerate in `metadata.fps`.  Note that the
    metadata attribute is lost in most subsequent `numpy` operations.
  )r  N)r   r  r   r   r_   r  )r	  rC   readerr   r   r	   r   O  s   $r   c                 K  s   t |\}}|jdd }|j}|tkrttj}nt|tjr(ttj}dt	|ddi|}t
| f||d|}|D ]}|| q@W d   dS 1 sSw   Y  dS )a~  Writes images to a compressed video file.

  >>> video = moving_circle((480, 640), num_images=60)
  >>> write_video('/tmp/v.mp4', video, fps=60, qp=18)
  >>> show_video(read_video('/tmp/v.mp4'))

  Args:
    path: Output video file.
    images: Iterable over video frames, e.g. a 4D array or a list of 2D or 3D
      arrays.
    **kwargs: Additional parameters for `VideoWriter`.
  Nrr   r  )rp   r   )ro   rp   r   rG   r   r   r   r   r   r  r   r  )rA   rn  rC   first_imagerp   r   writerr   r   r   r	   r   h  s   "r   r  r  c                K  sf   t |}t !}t|d|  }t|| fd|i| | W  d   S 1 s,w   Y  dS )aL  Returns a buffer containing a compressed video.

  The video container is 'mp4' except when `codec` is 'gif'.

  >>> video = read_video('/tmp/river.mp4')
  >>> data = compress_video(video, bps=10_000_000)
  >>> print(len(data))

  >>> data = compress_video(moving_circle((100, 100), num_images=10), fps=10)

  Args:
    images: Iterable over video frames.
    codec: Compression algorithm as defined by `ffmpeg -codecs` (e.g., 'h264',
      'hevc', 'vp9', or 'gif').
    **kwargs: Additional parameters for `VideoWriter`.

  Returns:
    A bytes buffer containing the compressed video.
  rR   r  N)r  r  r  r  r  r   r"  )rn  r  rC   r  r  r  r   r   r	   r!     s   
$r!   c                 K  sT   t  }t|d }||  t|fi |W  d   S 1 s#w   Y  dS )z8Returns video images from an MP4-compressed data buffer.zfile.mp4N)r  r  r  r  r  r   )r  rC   r  r  r   r   r	   r"     s
   

$r"   )rS  rT  loopautoplayr  r  c          
   	   C  s   t | d}t|tr| d}n|rd}nd}d| d| d| d|r(d	nd |r.d
nd 	}d| d| d}	|rFd| d|	 d}	|	S )a  Returns an HTML string with a video tag containing H264-encoded data.

  Args:
    data: MP4-compressed video bytes.
    width: Width of HTML video in pixels.
    height: Height of HTML video in pixels.
    title: Optional text shown centered above the video.
    border: If `bool`, whether to place a black boundary around the image, or if
      `str`, the boundary CSS style.
    loop: If True, the playback repeats forever.
    autoplay: If True, video playback starts without having to click.
  rY  rZ  r[  r   zcontrols width="r]  r^  zobject-fit:cover;"z loopz autoplay mutedz<video z+>
      <source src="data:video/mp4;base64,zV" type="video/mp4"/>
      This browser does not support the video tag.
      </video>r_  r`  ra  rb  )
r  rV  rW  rS  rT  r  r  rf  optionsr   r   r   r	   r$     s0   


r$   c                K  s   t | g|gfi |S )aU  Displays a video in the IPython notebook and optionally saves it to a file.

  See `show_videos`.

  >>> video = read_video('https://github.com/hhoppe/data/raw/main/video.mp4')
  >>> show_video(video, title='River video')

  >>> show_video(moving_circle((80, 80), num_images=10), fps=5, border=True)

  >>> show_video(read_video('/tmp/river.mp4'))

  Args:
    images: Iterable of video frames (e.g., a 4D array or a list of 2D or 3D
      arrays).
    title: Optional text shown centered above the video.
    **kwargs: See `show_videos`.

  Returns:
    html string if `return_html` is `True`.
  )r   )rn  rS  rC   r   r   r	   r     s   r   r   )rV  rW  ri  rj  r  r  r  r  rk  rl  rm  videos?Iterable[Iterable[_NDArray]] | Mapping[str, Iterable[_NDArray]]r  r  r  c             	     s  t | tr|durtdt|  }t|  }n*t| }|du r)dgt| nt|}t|t|krDtdt| dt| d|	dvrPtd|	 dg }t||D ]\}}t|d	d}t	|\}}t
|||jdd
 \ |r|jd k s |jd k r fdd|D }|d }t||||||	d}|rtjrt|	}ttj| |  }t|dd}|| W d   n1 sw   Y  |	dkr |jd kp݈|jd k}t| f|d|d|}nt| fd|i|}|| qWg }t||D ]/}ddfdd|D }|
r(d} d| d|
 d| }|d| d| d qd|}|r@|S t| dS ) a  Displays a row of videos in the IPython notebook.

  Creates HTML with `<video>` tags containing embedded H264-encoded bytestrings.
  If `codec` is set to 'gif', we instead use `<img>` tags containing embedded
  GIF-encoded bytestrings.  Note that the resulting GIF animations skip frames
  when the `fps` period is not a multiple of 10 ms units (GIF frame delay
  units).  Encoding at `fps` = 20.0, 25.0, or 50.0 works fine.

  If a directory has been specified using `set_show_save_dir`, also saves each
  titled video to a file in that directory based on its title.

  Args:
    videos: Iterable of videos, or dictionary of `{title: video}`.  Each video
      must be an iterable of images.  If a video object has a `metadata`
      (`VideoMetadata`) attribute, its `fps` field provides a default framerate.
    titles: Optional strings shown above the corresponding videos.
    width: Optional, overrides displayed width (in pixels).
    height: Optional, overrides displayed height (in pixels).
    downsample: If True, each video whose width or height is greater than the
      specified `width` or `height` is resampled to the display resolution. This
      improves antialiasing and reduces the size of the notebook.
    columns: Optional, maximum number of videos per row.
    fps: Frames-per-second framerate (default is 60.0 except 25.0 for GIF).
    bps: Bits-per-second bitrate (default None).
    qp: Quantization parameter for video compression quality (default None).
    codec: Compression algorithm; must be either 'h264' or 'gif'.
    ylabel: Text (rotated by 90 degrees) shown on the left of each row.
    html_class: CSS class name used in definition of HTML element.
    return_html: If `True` return the raw HTML `str` instead of displaying.
    **kwargs: Additional parameters (`border`, `loop`, `autoplay`) for
      `html_from_compressed_video`.

  Returns:
    html string if `return_html` is `True`.
  Nz;Cannot have both a video dictionary and a titles parameter.z2Number of videos does not match number of titles (rs  rt  >   r  r  zCodec z is neither h264 or gif.r  rr   r   r   c                   s   g | ]	}t | fqS r   r   r  )rw  rv  r   r	   r   >  s    zshow_videos.<locals>.<listcomp>)r  r  r  r  r  r   r   r  )rS  r3  rU  rS  r|  r   c                 3  r}  r~  r   r  r  r   r	   r
   W  r  zshow_videos.<locals>.<genexpr>r  r  r  r  r  r  r  )rs   r   rz   r  r  r  ry   r  r  ro   rh  rp   r!   rM   r<   r  r  r  rF   r!  r#   r$   r  rg   r  r   )r  rp  rV  rW  ri  rj  r  r  r  r  rk  rl  rm  rC   r  list_videosr  r  rS  r  r  r  r  rA   r  rU  html_stringr  r  r   r  r   )rw  r  rv  r	   r     s   
4 

)rA   r9   rB   r   rC   r   rD   r   )rA   r9   rD   rG   )rD   rJ   )rB   rN   rC   r   rD   rQ   r   )rY   rZ   r[   r\   rD   r]   )rh   rZ   rD   ri   )rp   rq   rD   rQ   )rB   r~   rD   rQ   )r   rN   rD   rQ   )r   r9   rD   rQ   )r   r   rD   rQ   )r   r3   rD   r5   )r   r2   rD   r4   )r   r2   r   r3   rD   r4   )r   r2   r   r3   rD   r4   )r   r2   rD   r4   )r   )rp   rq   r   r3   rD   r4   )r   r   )rp   rq   r   r   r   r3   rD   r4   )r   r2   rD   r4   )r   r2   rD   r4   )r   r2   rD   r4   )r   r2   r   rJ   rD   r   )r   r2   rp   rq   rD   r4   )r  r  rp   rq   rD   r4   )r	  r9   rD   rG   )r	  r9   rD   r  )r	  r9   rD   r  )rA   r9   rD   r  )r	  r9   r1  rG   r   r3   rD   r4   )r2  )
rA   r9   r   r2   r3  rN   rC   r   rD   rQ   )
r   r2   r8  r;  r9  r;  r:  r<  rD   r4   )r   r2   r3  rN   rC   r   rD   r  )NT)r  r  r   r3   r1  rG   rD   r4   )r  r  rV  r   rW  r   rS  rJ   rT  rX  rU  rG   r3  rN   rD   rN   )rV  r\   rW  r\   rp   rq   rD   rq   )r   r2   rS  rJ   rC   r   rD   rJ   )rn  ro  rp  rq  rV  r\   rW  r\   ri  rG   rj  r\   r8  r;  r9  r;  r:  r<  rT  rX  rk  rN   rl  rN   rU  rr  rm  rG   rD   rJ   )r  rN   rD   rN   r  )rD   rG   )rA   r9   rD   r   )r	  r9   rC   r   rD   r  )rA   r9   rn  r  rC   r   rD   rQ   )rn  r  r  rN   rC   r   rD   r  )r  r  rC   r   rD   r4   )r  r  rV  r   rW  r   rS  rJ   rT  rX  r  rG   r  rG   rD   rN   )rn  r  rS  rJ   rC   r   rD   rJ   )r  r  rp  rq  rV  r\   rW  r\   ri  rG   rj  r\   r  r;  r  r\   r  r\   r  rN   rk  rN   rl  rN   rm  rG   rC   r   rD   rJ   )r0  
__future__r   __docformat____version__r_   r  __version_info__rc  collections.abcr   r   r   r   r   
contextlibre   r   rL  r`   r  rt   osr  r  r  rK   r   rU   r  typingr   urllib.requestr  IPython.displayr   rG  numpyr   numpy.typingnpt	PIL.Imager   PIL.ImageOpsrF  r   r   __all__TYPE_CHECKING	ArrayLiker2   	DTypeLiker3   ndarrayr4   r   r5   TypeVarr  r6   UnionrN   PathLiker9   r7   rM   rF   rI   rP   rX   rg   ro   r}   r   r   r0   r+   r,   r   r   r(   r   r)   r*   r-   r.   r   r   linalginvr   r   r   r   	transposer   r   r   r   r   r   r%   r&   r  r  contextmanagerr  r#  r/   r   r   r'   r   r    r#   rh  r   r   r  r  r1   
NamedTupler   r  r  r   r   NDArrayr  r   r   r!   r"   r$   r   r   r   r   r   r	   <module>   sn  T
!



















	;
	*



*$-* 
/  u/