Commit 3f02b898 authored by moto's avatar moto Committed by Facebook GitHub Bot
Browse files

Update hardware accelerated video processing tutorial (#3050)

Summary:
Par https://github.com/pytorch/audio/issues/3040 and https://github.com/pytorch/audio/issues/3041, it turned out Google Colab now has FFmpeg with GPU decoder/encoder preinstalled, and installing FFmpeg manually corrups the environment.

This commit updates the tutorial by extracting and moving the how-to-install part to installation/build section.

closes https://github.com/pytorch/audio/issues/3041
closes https://github.com/pytorch/audio/issues/3040

Pull Request resolved: https://github.com/pytorch/audio/pull/3050

Reviewed By: nateanl

Differential Revision: D43166054

Pulled By: mthrok

fbshipit-source-id: 32667f292a796344d5fcde86e8231e15ad904e58
parent fadb5ae5
Enabling GPU video decoder/encoder
==================================
TorchAudio can make use of hardware-based video decoding and encoding supported by underlying FFmpeg libraries that are linked at runtime.
Using NVIDIA's GPU decoder and encoder, it is also possible to pass around CUDA Tensor directly, that is decode video into CUDA tensor or encode video from CUDA tensor, without moving data from/to CPU.
This improves the video throughput significantly. However, please note that not all the video formats are supported by hardware acceleration.
This page goes through how to build FFmpeg with hardware acceleration. For the detail on the performance of GPU decoder and encoder please see `Hardware-Accelerated Video Decoding and Encoding <./hw_acceleration_tutorial.html>`_
Overview
--------
Using them in TorchAduio requires additional FFmpeg configuration.
In the following, we look into how to enable GPU video decoding with `NVIDIA's Video codec SDK <https://developer.nvidia.com/nvidia-video-codec-sdk>`_.
To use NVENC/NVDEC with TorchAudio, the following items are required.
1. NVIDIA GPU with hardware video decoder/encoder.
2. FFmpeg libraries compiled with NVDEC/NVENC support. †
3. PyTorch / TorchAudio with CUDA support.
TorchAudio’s official binary distributions are compiled to work with FFmpeg 4 libraries, and they contain the logic required for hardware-based decoding/encoding.
In the following, we build FFmpeg 4 libraries with NVDEC/NVENC support. If you would like to use FFmpeg 5, then you need to build TorchAudio with it.
The following procedure was tested on Ubuntu.
† For details on NVDEC/NVENC and FFmpeg, please refer to the following articles.
- https://docs.nvidia.com/video-technologies/video-codec-sdk/nvdec-video-decoder-api-prog-guide/
- https://docs.nvidia.com/video-technologies/video-codec-sdk/ffmpeg-with-nvidia-gpu/#compiling-ffmpeg
- https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/
Check the GPU and CUDA version
------------------------------
First, check the available GPU. Here, we have Tesla T4 with CUDA Toolkit 11.2 installed.
.. code-block::
$ nvidia-smi
Fri Oct 7 13:01:26 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |
| N/A 56C P8 10W / 70W | 0MiB / 15109MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
Checking the compute capability
-------------------------------
Later, we need the version of compute capability supported by this GPU. The following page lists the GPUs and corresponding compute capabilities. The compute capability of T4 is ``7.5``.
https://developer.nvidia.com/cuda-gpus
Install NVIDIA Video Codec Headers
----------------------------------
To build FFmpeg with NVDEC/NVENC, we first need to install the headers that FFmpeg uses to interact with Video Codec SDK.
Since we have CUDA 11 working in the system, we use one of ``n11`` tag.
.. code-block:: bash
git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
cd nv-codec-headers
git checkout n11.0.10.1
sudo make install
The location of installation can be changed with ``make PREFIX=<DESIRED_DIRECTORY> install``.
.. code-block:: text
Cloning into 'nv-codec-headers'...
remote: Enumerating objects: 819, done.
remote: Counting objects: 100% (819/819), done.
remote: Compressing objects: 100% (697/697), done.
remote: Total 819 (delta 439), reused 0 (delta 0)
Receiving objects: 100% (819/819), 156.42 KiB | 410.00 KiB/s, done.
Resolving deltas: 100% (439/439), done.
Note: checking out 'n11.0.10.1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 315ad74 add cuMemcpy
sed 's#@@PREFIX@@#/usr/local#' ffnvcodec.pc.in > ffnvcodec.pc
install -m 0755 -d '/usr/local/include/ffnvcodec'
install -m 0644 include/ffnvcodec/*.h '/usr/local/include/ffnvcodec'
install -m 0755 -d '/usr/local/lib/pkgconfig'
install -m 0644 ffnvcodec.pc '/usr/local/lib/pkgconfig'
Install FFmpeg dependencies
---------------------------
Next, we install tools and libraries required during the FFmpeg build.
The minimum requirement is `Yasm <https://yasm.tortall.net/>`_.
Here we additionally install H264 video codec and HTTPS protocol,
which we use later for verifying the installation.
.. code-block:: bash
sudo apt -qq update
sudo apt -qq install -y yasm libx264-dev libgnutls28-dev
.. code-block:: text
... Omitted for brevity ...
STRIP install-libavutil-shared
Setting up libx264-dev:amd64 (2:0.152.2854+gite9a5903-2) ...
Setting up yasm (1.3.0-2build1) ...
Setting up libunbound2:amd64 (1.6.7-1ubuntu2.5) ...
Setting up libp11-kit-dev:amd64 (0.23.9-2ubuntu0.1) ...
Setting up libtasn1-6-dev:amd64 (4.13-2) ...
Setting up libtasn1-doc (4.13-2) ...
Setting up libgnutlsxx28:amd64 (3.5.18-1ubuntu1.6) ...
Setting up libgnutls-dane0:amd64 (3.5.18-1ubuntu1.6) ...
Setting up libgnutls-openssl27:amd64 (3.5.18-1ubuntu1.6) ...
Setting up libgmpxx4ldbl:amd64 (2:6.1.2+dfsg-2) ...
Setting up libidn2-dev:amd64 (2.0.4-1.1ubuntu0.2) ...
Setting up libidn2-0-dev (2.0.4-1.1ubuntu0.2) ...
Setting up libgmp-dev:amd64 (2:6.1.2+dfsg-2) ...
Setting up nettle-dev:amd64 (3.4.1-0ubuntu0.18.04.1) ...
Setting up libgnutls28-dev:amd64 (3.5.18-1ubuntu1.6) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Processing triggers for libc-bin (2.27-3ubuntu1.6) ...
Build FFmpeg with NVDEC/NVENC support
-------------------------------------
Next we download the source code of FFmpeg 4. We use 4.4.2 here. Any version later than 4.1 should work with TorchAudio binary distributions. If you want to use FFmpeg 5, then you need to build TorchAudio after building FFmpeg.
.. code-block:: bash
wget -q https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n4.4.2.tar.gz
tar -xf n4.4.2.tar.gz
cd FFmpeg-n4.4.2
Next we configure FFmpeg build. Note the following:
1. We provide flags like ``-I/usr/local/cuda/include``, ``-L/usr/local/cuda/lib64`` to let the build process know where the CUDA libraries are found.
2. We provide flags like ``--enable-nvdec`` and ``--enable-nvenc`` to enable NVDEC/NVENC.
3. We also provide NVCC flags with compute capability ``75``, which corresponds to ``7.5`` of T4. †
4. We install the library in ``/usr/lib/``.
.. note::
† The configuration script verifies NVCC by compiling a sample code. By default it uses old compute capability such as ``30``, which is no longer supported by CUDA 11. So it is required to set a correct compute capability.
.. code-block:: bash
prefix=/usr/
ccap=75
./configure \
--prefix="${prefix}" \
--extra-cflags='-I/usr/local/cuda/include' \
--extra-ldflags='-L/usr/local/cuda/lib64' \
--nvccflags="-gencode arch=compute_${ccap},code=sm_${ccap} -O2" \
--disable-doc \
--enable-decoder=aac \
--enable-decoder=h264 \
--enable-decoder=h264_cuvid \
--enable-decoder=rawvideo \
--enable-indev=lavfi \
--enable-encoder=libx264 \
--enable-encoder=h264_nvenc \
--enable-demuxer=mov \
--enable-muxer=mp4 \
--enable-filter=scale \
--enable-filter=testsrc2 \
--enable-protocol=file \
--enable-protocol=https \
--enable-gnutls \
--enable-shared \
--enable-gpl \
--enable-nonfree \
--enable-cuda-nvcc \
--enable-libx264 \
--enable-nvenc \
--enable-cuvid \
--enable-nvdec
.. code-block:: text
install prefix /usr/
source path .
C compiler gcc
C library glibc
ARCH x86 (generic)
big-endian no
runtime cpu detection yes
standalone assembly yes
x86 assembler yasm
MMX enabled yes
MMXEXT enabled yes
3DNow! enabled yes
3DNow! extended enabled yes
SSE enabled yes
SSSE3 enabled yes
AESNI enabled yes
AVX enabled yes
AVX2 enabled yes
AVX-512 enabled yes
XOP enabled yes
FMA3 enabled yes
FMA4 enabled yes
i686 features enabled yes
CMOV is fast yes
EBX available yes
EBP available yes
debug symbols yes
strip symbols yes
optimize for size no
optimizations yes
static no
shared yes
postprocessing support no
network support yes
threading support pthreads
safe bitstream reader yes
texi2html enabled no
perl enabled yes
pod2man enabled yes
makeinfo enabled no
makeinfo supports HTML no
External libraries:
alsa libx264 lzma
bzlib libxcb zlib
gnutls libxcb_shape
iconv libxcb_xfixes
External libraries providing hardware acceleration:
cuda cuvid nvenc
cuda_llvm ffnvcodec v4l2_m2m
cuda_nvcc nvdec
Libraries:
avcodec avformat swscale
avdevice avutil
avfilter swresample
Programs:
ffmpeg ffprobe
Enabled decoders:
aac hevc rawvideo
av1 mjpeg vc1
h263 mpeg1video vp8
h264 mpeg2video vp9
h264_cuvid mpeg4
Enabled encoders:
h264_nvenc libx264
Enabled hwaccels:
av1_nvdec mpeg1_nvdec vp8_nvdec
h264_nvdec mpeg2_nvdec vp9_nvdec
hevc_nvdec mpeg4_nvdec wmv3_nvdec
mjpeg_nvdec vc1_nvdec
Enabled parsers:
h263 mpeg4video vp9
Enabled demuxers:
mov
Enabled muxers:
mov mp4
Enabled protocols:
file tcp
https tls
Enabled filters:
aformat hflip transpose
anull null trim
atrim scale vflip
format testsrc2
Enabled bsfs:
aac_adtstoasc null vp9_superframe_split
h264_mp4toannexb vp9_superframe
Enabled indevs:
lavfi
Enabled outdevs:
License: nonfree and unredistributable
Now we build and install
.. code-block:: bash
make clean
make -j
sudo make install
.. code-block:: text
... Omitted for brevity ...
INSTALL libavdevice/libavdevice.so
INSTALL libavfilter/libavfilter.so
INSTALL libavformat/libavformat.so
INSTALL libavcodec/libavcodec.so
INSTALL libswresample/libswresample.so
INSTALL libswscale/libswscale.so
INSTALL libavutil/libavutil.so
INSTALL install-progs-yes
INSTALL ffmpeg
INSTALL ffprobe
Checking the intallation
------------------------
To verify that the FFmpeg we built have CUDA support, we can check the list of available decoders and encoders.
.. code-block:: bash
ffprobe -hide_banner -decoders | grep h264
.. code-block:: text
VFS..D h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
V..... h264_cuvid Nvidia CUVID H264 decoder (codec h264)
.. code-block:: bash
ffmpeg -hide_banner -encoders | grep 264
.. code-block:: text
V..... libx264 libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)
V....D h264_nvenc NVIDIA NVENC H.264 encoder (codec h264)
The following command fetches video from remote server, decode with NVDEC (cuvid) and re-encode with NVENC. If this command does not work, then there is an issue with FFmpeg installation, and TorchAudio would not be able to use them either.
.. code-block:: bash
$ src="https://download.pytorch.org/torchaudio/tutorial-assets/stream-api/NASAs_Most_Scientifically_Complex_Space_Observatory_Requires_Precision-MP4_small.mp4"
$ ffmpeg -hide_banner -y -vsync 0 \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-resize 360x240 \
-i "${src}" \
-c:a copy \
-c:v h264_nvenc \
-b:v 5M test.mp4
Note that there is ``Stream #0:0 -> #0:0 (h264 (h264_cuvid) -> h264 (h264_nvenc))``, which means that video is decoded with ``h264_cuvid`` decoder and ``h264_nvenc`` encoder.
.. code-block::
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'https://download.pytorch.org/torchaudio/tutorial-assets/stream-api/NASAs_Most_Scientifically_Complex_Space_Observatory_Requires_Precision-MP4_small.mp4':
Metadata:
major_brand : mp42
minor_version : 512
compatible_brands: mp42iso2avc1mp41
encoder : Lavf58.76.100
Duration: 00:03:26.04, start: 0.000000, bitrate: 1294 kb/s
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 960x540 [SAR 1:1 DAR 16:9], 1156 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
Metadata:
handler_name : ?Mainconcept Video Media Handler
vendor_id : [0][0][0][0]
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
handler_name : #Mainconcept MP4 Sound Media Handler
vendor_id : [0][0][0][0]
Stream mapping:
Stream #0:0 -> #0:0 (h264 (h264_cuvid) -> h264 (h264_nvenc))
Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
Output #0, mp4, to 'test.mp4':
Metadata:
major_brand : mp42
minor_version : 512
compatible_brands: mp42iso2avc1mp41
encoder : Lavf58.76.100
Stream #0:0(eng): Video: h264 (Main) (avc1 / 0x31637661), cuda(tv, bt709, progressive), 360x240 [SAR 1:1 DAR 3:2], q=2-31, 5000 kb/s, 29.97 fps, 30k tbn (default)
Metadata:
handler_name : ?Mainconcept Video Media Handler
vendor_id : [0][0][0][0]
encoder : Lavc58.134.100 h264_nvenc
Side data:
cpb: bitrate max/min/avg: 0/0/5000000 buffer size: 10000000 vbv_delay: N/A
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
handler_name : #Mainconcept MP4 Sound Media Handler
vendor_id : [0][0][0][0]
frame= 6175 fps=1712 q=11.0 Lsize= 37935kB time=00:03:26.01 bitrate=1508.5kbits/s speed=57.1x
video:34502kB audio:3234kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.526932%
Using the GPU decoder/encoder from TorchAudio
---------------------------------------------
Checking the installation
~~~~~~~~~~~~~~~~~~~~~~~~~
Once the FFmpeg is properly working with hardware acceleration, we need to check if TorchAudio can pick it up correctly.
There are utility functions to query the capability of FFmpeg in :py:mod:`torchaudio.utils.ffmpeg_utils`.
You can first use :py:func:`~torchaudio.utils.ffmpeg_utils.get_video_decoders` and :py:func:`~torchaudio.utils.ffmpeg_utils.get_video_encoders` to check if GPU decoders and encoders (such as ``h264_cuvid`` and ``h264_nvenc``) are listed.
It is often the case where there are multiple FFmpeg installations in the system, and TorchAudio is loading one different than expected. In such cases, use of ``ffmpeg`` to check the installation does not help. You can use functions like :py:func:`~torchaudio.utils.ffmpeg_utils.get_build_config` and :py:func:`~torchaudio.utils.ffmpeg_utils.get_versions` to get information about FFmpeg libraries TorchAudio loaded.
.. code-block:: python
from torchaudio.utils import ffmpeg_utils
print("Library versions:")
print(ffmpeg_utils.get_versions())
print("\nBuild config:")
print(ffmpeg_utils.get_build_config())
print("\nDecoders:")
print([k for k in ffmpeg_utils.get_video_decoders().keys() if "cuvid" in k])
print("\nEncoders:")
print([k for k in ffmpeg_utils.get_video_encoders().keys() if "nvenc" in k])
.. code-block:: text
Library versions:
{'libavutil': (56, 31, 100), 'libavcodec': (58, 54, 100), 'libavformat': (58, 29, 100), 'libavfilter': (7, 57, 100), 'libavdevice': (58, 8, 100)}
Build config:
--prefix=/usr --extra-version=0ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
Decoders:
['h264_cuvid', 'hevc_cuvid', 'mjpeg_cuvid', 'mpeg1_cuvid', 'mpeg2_cuvid', 'mpeg4_cuvid', 'vc1_cuvid', 'vp8_cuvid', 'vp9_cuvid']
Encoders:
['h264_nvenc', 'nvenc', 'nvenc_h264', 'nvenc_hevc', 'hevc_nvenc']
Using the hardware decoder
~~~~~~~~~~~~~~~~~~~~~~~~~~
Once the installation and the runtime linking work fine, then you can test the GPU decoding with the following.
For the detail on the performance of GPU decoder and encoder please see `Hardware-Accelerated Video Decoding and Encoding <./hw_acceleration_tutorial.html>`_
.. code-block:: python
from torchaudio.io import StreamReader
src = "https://download.pytorch.org/torchaudio/tutorial-assets/stream-api/NASAs_Most_Scientifically_Complex_Space_Observatory_Requires_Precision-MP4_small.mp4"
s = StreamReader(src)
s.add_video_stream(
5,
decoder="h264_cuvid",
hw_accel="cuda:0",
decoder_option={
"resize": "360x240",
},
)
s.fill_buffer()
chunk, = s.pop_chunks()
print(' - Chunk:', chunk.shape, chunk.device, chunk.dtype)
.. code-block:: text
- Chunk: torch.Size([5, 3, 240, 360]) cuda:0 torch.uint8
......@@ -6,89 +6,17 @@
"id": "3BxT9HiUjMyv"
},
"source": [
"# Hardware-Accelerated Video Decoding and Encoding\n",
"# GPU video decoder/encoder\n",
"\n",
"**Author**: [Moto Hira](moto@meta.com)\n",
"\n",
"This tutorial shows how to use NVIDIA's hardware video decoder (NVDEC) and encoder (NVENC) with TorchAudio.\n",
"\n",
"Using hardware encoder/decoder improves the speed of loading and saving certain types of videos. Using them in TorchAduio requires additional FFmpeg configuration. This tutorial goes over how to compile FFmpeg, and compare the speed it takes to process video.\n",
"Using hardware encoder/decoder improves the speed of loading and saving certain types of videos.\n",
"\n",
"**WARNING**\n",
"Using them in TorchAduio requires FFmpeg built with NVENC/NVDEC support. Google Colab has such FFmpeg pre-installed, so you can [run this tutorial on Google Colab](https://colab.research.google.com/drive/1DDah_IaGULEO66CfQWltRqaVheBkiXdN#sandboxMode=true).\n",
"\n",
"> This tutorial instsalls FFmpeg in system directory.\n",
"> If you run this tutorial on your system, please adjust the build configuration accordingly.\n",
"\n",
"**NOTE**\n",
"\n",
"> This tutorial was authored in Google Colab, and is tailored to Google Colab's specifications. Please check out this tutorial in [Google Colab](https://colab.research.google.com/drive/1DDah_IaGULEO66CfQWltRqaVheBkiXdN#sandboxMode=true).\n",
"\n",
"To use NVENC/NVDEC with TorchAudio, the following items are required.\n",
"\n",
"1. NVIDIA GPU with hardware video decoder/encoder.\n",
"2. FFmpeg libraries compiled with NVDEC/NVENC support. †\n",
"3. PyTorch / TorchAudio with CUDA support.\n",
"\n",
"TorchAudio's official binary distributions are compiled with FFmpeg 4 libraries, and they contain the logic required for hardware-based decoding/encoding.\n",
"\n",
"In the following sections, we build FFmpeg 4 libraries with NVDEC/NVENC support, then we demonstrate the performance imrovement using TorchAudio's `StreamReader`/`StreamWriter`.\n",
"\n",
"† For details on NVDEC/NVENC and FFmpeg, please refer to the following articles.\n",
"\n",
"* https://docs.nvidia.com/video-technologies/video-codec-sdk/nvdec-video-decoder-api-prog-guide/\n",
"* https://docs.nvidia.com/video-technologies/video-codec-sdk/ffmpeg-with-nvidia-gpu/#compiling-ffmpeg\n",
"* https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "08XIDshiiFp-"
},
"source": [
"## Check the available GPU"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gCegZlbgutNM",
"outputId": "0eca8ead-4671-4b83-ca9b-a602642844a5"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Fri Oct 7 13:01:26 2022 \n",
"+-----------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 |\n",
"|-------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|===============================+======================+======================|\n",
"| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n",
"| N/A 56C P8 10W / 70W | 0MiB / 15109MiB | 0% Default |\n",
"| | | N/A |\n",
"+-------------------------------+----------------------+----------------------+\n",
" \n",
"+-----------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=============================================================================|\n",
"| No running processes found |\n",
"+-----------------------------------------------------------------------------+\n"
]
}
],
"source": [
"!nvidia-smi"
"If you want to enable GPU decoding/encoding, please refer to [Enabling GPU video decoder/encoder](./build.ffmpeg.html)."
]
},
{
......@@ -96,7 +24,7 @@
"source": [
"## Update PyTorch and TorchAudio with nightly builds\n",
"\n",
"Until TorchAudio 0.13 is released, we need to use the nightly builds of PyTorch and TorchAudio."
"Until PyTorch 2.0 is released, we need to use the nightly builds of PyTorch and TorchAudio."
],
"metadata": {
"id": "8EI-DwaeQbjp"
......@@ -110,436 +38,146 @@
"base_uri": "https://localhost:8080/"
},
"id": "fACIAl1dgYt-",
"outputId": "7ff2cb88-33e5-4b8c-9542-4f53cce09cfa"
"outputId": "94c153e5-5260-4b83-9bc4-64d40c23e25f"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/, https://download.pytorch.org/whl/nightly/cu116\n",
"Collecting torch\n",
" Downloading https://download.pytorch.org/whl/nightly/cu116/torch-1.14.0.dev20221007%2Bcu116-cp37-cp37m-linux_x86_64.whl (2286.1 MB)\n",
"\u001b[?25l\n",
"\u001b[?25hCollecting torchaudio\n",
" Downloading https://download.pytorch.org/whl/nightly/cu116/torchaudio-0.13.0.dev20221006%2Bcu116-cp37-cp37m-linux_x86_64.whl (4.2 MB)\n",
"\u001b[?25l\n",
"\u001b[?25hRequirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch) (4.1.1)\n",
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/, https://download.pytorch.org/whl/nightly/cu117\n",
"Collecting torch\n",
" Downloading https://download.pytorch.org/whl/nightly/cu116/torch-1.13.0.dev20221006%2Bcu116-cp37-cp37m-linux_x86_64.whl (1983.0 MB)\n",
"\u001b[?25l\n",
"\u001b[?25hInstalling collected packages: torch, torchaudio\n",
"Successfully installed torch-1.13.0.dev20221006+cu116 torchaudio-0.13.0.dev20221006+cu116\n"
" Downloading https://download.pytorch.org/whl/nightly/cu117/torch-2.0.0.dev20230209%2Bcu117-cp38-cp38-linux_x86_64.whl (1837.7 MB)\n",
"Collecting torchaudio\n",
" Downloading https://download.pytorch.org/whl/nightly/cu117/torchaudio-2.0.0.dev20230208%2Bcu117-cp38-cp38-linux_x86_64.whl (4.4 MB)\n",
"Requirement already satisfied: filelock in /usr/local/lib/python3.8/dist-packages (from torch) (3.9.0)\n",
"Collecting pytorch-triton==2.0.0+0d7e753227\n",
" Downloading https://download.pytorch.org/whl/nightly/pytorch_triton-2.0.0%2B0d7e753227-cp38-cp38-linux_x86_64.whl (18.7 MB)\n",
"Requirement already satisfied: typing-extensions in /usr/local/lib/python3.8/dist-packages (from torch) (4.4.0)\n",
"Requirement already satisfied: networkx in /usr/local/lib/python3.8/dist-packages (from torch) (3.0)\n",
"Requirement already satisfied: sympy in /usr/local/lib/python3.8/dist-packages (from torch) (1.7.1)\n",
"Requirement already satisfied: cmake in /usr/local/lib/python3.8/dist-packages (from pytorch-triton==2.0.0+0d7e753227->torch) (3.22.6)\n",
"Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.8/dist-packages (from sympy->torch) (1.2.1)\n",
"Installing collected packages: pytorch-triton, torch, torchaudio\n",
"Successfully installed pytorch-triton-2.0.0+0d7e753227 torch-2.0.0.dev20230209+cu117 torchaudio-2.0.0.dev20230208+cu117\n"
]
}
],
"source": [
"!pip uninstall -y -q torch torchaudio torchvision torchtext\n",
"!pip install --progress-bar off --pre torch torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/cu116 2> /dev/null"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "RAziwx_MqJzr"
},
"source": [
"## Build FFmpeg libraries with Nvidia NVDEC/NVENC support\n"
"!pip install --progress-bar off --pre torch torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/cu117 2> /dev/null"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VcKsO-zurtWM"
},
"source": [
"### Install NVIDIA Video Codec Headers\n",
"\n",
"To build FFmpeg with NVDEC/NVENC, we first install the headers that FFmpeg uses to interact with Video Codec SDK."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "vgbusLNCq2mV",
"outputId": "04b9c2b6-bc18-4dd0-ea8f-4b320559ebb3"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cloning into 'nv-codec-headers'...\n",
"remote: Enumerating objects: 819, done.\u001b[K\n",
"remote: Counting objects: 100% (819/819), done.\u001b[K\n",
"remote: Compressing objects: 100% (697/697), done.\u001b[K\n",
"remote: Total 819 (delta 439), reused 0 (delta 0)\u001b[K\n",
"Receiving objects: 100% (819/819), 156.42 KiB | 410.00 KiB/s, done.\n",
"Resolving deltas: 100% (439/439), done.\n",
"Note: checking out 'n11.0.10.1'.\n",
"\n",
"You are in 'detached HEAD' state. You can look around, make experimental\n",
"changes and commit them, and you can discard any commits you make in this\n",
"state without impacting any branches by performing another checkout.\n",
"\n",
"If you want to create a new branch to retain commits you create, you may\n",
"do so (now or later) by using -b with the checkout command again. Example:\n",
"\n",
" git checkout -b <new-branch-name>\n",
"\n",
"HEAD is now at 315ad74 add cuMemcpy\n",
"sed 's#@@PREFIX@@#/usr/local#' ffnvcodec.pc.in > ffnvcodec.pc\n",
"install -m 0755 -d '/usr/local/include/ffnvcodec'\n",
"install -m 0644 include/ffnvcodec/*.h '/usr/local/include/ffnvcodec'\n",
"install -m 0755 -d '/usr/local/lib/pkgconfig'\n",
"install -m 0644 ffnvcodec.pc '/usr/local/lib/pkgconfig'\n"
]
}
"## Install third party libraries and download assets"
],
"source": [
"!git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git\n",
"# Note: Google Colab's GPU has NVENC API ver 11.0, so we checkout 11.0 tag.\n",
"!cd nv-codec-headers && git checkout n11.0.10.1 && sudo make install"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PWT0m_LGq_GE"
},
"source": [
"### Download FFmpeg source code\n",
"\n",
"Next we download the source code of FFmpeg 4. Any version later than 4.1 should work. We use 4.4.2 here."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"id": "AKERwitAzfLo"
},
"outputs": [],
"source": [
"!wget -q https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n4.4.2.tar.gz\n",
"!tar -xf n4.4.2.tar.gz\n",
"!mv FFmpeg-n4.4.2 ffmpeg"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "TpWDpxBvDy-b"
},
"source": [
"### Install FFmpeg build and runtime dependencies\n",
"\n",
"In the later test, we use H264 video codec and HTTPS protocol, so we install the libraries for them here."
]
"id": "uC1wdJP35Z7l"
}
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 8,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Vn50oz2UvvPP",
"outputId": "b2e695d9-c953-4370-fb8d-92cdd8a832be"
"id": "lbA3S6p_Z2lI",
"outputId": "d8282d99-3090-4cea-b66f-91da45b21764"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"STRIP\tinstall-libavutil-shared\n",
"\n",
"... Omitted for brevity ...\n",
"\n",
"Setting up libx264-dev:amd64 (2:0.152.2854+gite9a5903-2) ...\n",
"Setting up yasm (1.3.0-2build1) ...\n",
"Setting up libunbound2:amd64 (1.6.7-1ubuntu2.5) ...\n",
"Setting up libp11-kit-dev:amd64 (0.23.9-2ubuntu0.1) ...\n",
"Setting up libtasn1-6-dev:amd64 (4.13-2) ...\n",
"Setting up libtasn1-doc (4.13-2) ...\n",
"Setting up libgnutlsxx28:amd64 (3.5.18-1ubuntu1.6) ...\n",
"Setting up libgnutls-dane0:amd64 (3.5.18-1ubuntu1.6) ...\n",
"Setting up libgnutls-openssl27:amd64 (3.5.18-1ubuntu1.6) ...\n",
"Setting up libgmpxx4ldbl:amd64 (2:6.1.2+dfsg-2) ...\n",
"Setting up libidn2-dev:amd64 (2.0.4-1.1ubuntu0.2) ...\n",
"Setting up libidn2-0-dev (2.0.4-1.1ubuntu0.2) ...\n",
"Setting up libgmp-dev:amd64 (2:6.1.2+dfsg-2) ...\n",
"Setting up nettle-dev:amd64 (3.4.1-0ubuntu0.18.04.1) ...\n",
"Setting up libgnutls28-dev:amd64 (3.5.18-1ubuntu1.6) ...\n",
"Processing triggers for man-db (2.8.3-2ubuntu0.1) ...\n",
"Processing triggers for libc-bin (2.27-3ubuntu1.6) ...\n"
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Collecting boto3\n",
" Downloading boto3-1.26.67-py3-none-any.whl (132 kB)\n",
"Collecting botocore<1.30.0,>=1.29.67\n",
" Downloading botocore-1.29.67-py3-none-any.whl (10.4 MB)\n",
"Collecting jmespath<2.0.0,>=0.7.1\n",
" Downloading jmespath-1.0.1-py3-none-any.whl (20 kB)\n",
"Collecting s3transfer<0.7.0,>=0.6.0\n",
" Downloading s3transfer-0.6.0-py3-none-any.whl (79 kB)\n",
"Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /usr/local/lib/python3.8/dist-packages (from botocore<1.30.0,>=1.29.67->boto3) (2.8.2)\n",
"Collecting urllib3<1.27,>=1.25.4\n",
" Downloading urllib3-1.26.14-py2.py3-none-any.whl (140 kB)\n",
"Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.8/dist-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.30.0,>=1.29.67->boto3) (1.15.0)\n",
"Installing collected packages: urllib3, jmespath, botocore, s3transfer, boto3\n",
" Attempting uninstall: urllib3\n",
" Found existing installation: urllib3 1.24.3\n",
" Uninstalling urllib3-1.24.3:\n",
" Successfully uninstalled urllib3-1.24.3\n",
"Successfully installed boto3-1.26.67 botocore-1.29.67 jmespath-1.0.1 s3transfer-0.6.0 urllib3-1.26.14\n"
]
}
],
"source": [
"!apt -qq update\n",
"!apt -qq install -y yasm libx264-dev libgnutls28-dev"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "wL3lAZWPTJaN"
},
"source": [
"### Configure FFmpeg build with Nvidia CUDA hardware support\n",
"\n",
"Next we configure FFmpeg build. Note the following:\n",
"\n",
"1. We provide flags like `-I/usr/local/cuda/include`, `-L/usr/local/cuda/lib64` to let the build process know where the CUDA libraries are found.\n",
"2. We provide flags like `--enable-nvdec` and `--enable-nvenc` to enable NVDEC/NVENC. Please check out the Transcoding Guide† for the detail.\n",
"3. We also provide NVCC flags with compute capability 37. \n",
"This is because by default the configuration script verifies NVCC by compiling sample code targeting compute capability 30, which is too old for CUDA 11.\n",
"4. Many features are disabled to reduce the compilation time.\n",
"5. We install the library in `/usr/lib/`, which is one of the active search path of the dynamic loader. \n",
"Doing so allows the resulting libraries to be found without requiring a restart of the current session. This might be an undesirable location, e.g. when one isn't using a disposable VM.\n",
"\n",
"† NVIDIA FFmpeg Transcoding Guide https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/"
"!pip3 install --progress-bar off boto3 2> /dev/null"
]
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 10,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "KZr8bMdztRz1",
"outputId": "d542338b-bfcd-4176-c349-4a9235fcf411"
"id": "d0GYPyGGTz-q"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"env: ccap=37\n",
"install prefix /usr/\n",
"source path .\n",
"C compiler gcc\n",
"C library glibc\n",
"ARCH x86 (generic)\n",
"big-endian no\n",
"runtime cpu detection yes\n",
"standalone assembly yes\n",
"x86 assembler yasm\n",
"MMX enabled yes\n",
"MMXEXT enabled yes\n",
"3DNow! enabled yes\n",
"3DNow! extended enabled yes\n",
"SSE enabled yes\n",
"SSSE3 enabled yes\n",
"AESNI enabled yes\n",
"AVX enabled yes\n",
"AVX2 enabled yes\n",
"AVX-512 enabled yes\n",
"XOP enabled yes\n",
"FMA3 enabled yes\n",
"FMA4 enabled yes\n",
"i686 features enabled yes\n",
"CMOV is fast yes\n",
"EBX available yes\n",
"EBP available yes\n",
"debug symbols yes\n",
"strip symbols yes\n",
"optimize for size no\n",
"optimizations yes\n",
"static no\n",
"shared yes\n",
"postprocessing support no\n",
"network support yes\n",
"threading support pthreads\n",
"safe bitstream reader yes\n",
"texi2html enabled no\n",
"perl enabled yes\n",
"pod2man enabled yes\n",
"makeinfo enabled no\n",
"makeinfo supports HTML no\n",
"\n",
"External libraries:\n",
"alsa libx264 lzma\n",
"bzlib libxcb zlib\n",
"gnutls libxcb_shape\n",
"iconv libxcb_xfixes\n",
"\n",
"External libraries providing hardware acceleration:\n",
"cuda cuvid nvenc\n",
"cuda_llvm ffnvcodec v4l2_m2m\n",
"cuda_nvcc nvdec\n",
"\n",
"Libraries:\n",
"avcodec avformat swscale\n",
"avdevice avutil\n",
"avfilter swresample\n",
"\n",
"Programs:\n",
"ffmpeg ffprobe\n",
"\n",
"Enabled decoders:\n",
"aac hevc rawvideo\n",
"av1 mjpeg vc1\n",
"h263 mpeg1video vp8\n",
"h264 mpeg2video vp9\n",
"h264_cuvid mpeg4\n",
"\n",
"Enabled encoders:\n",
"h264_nvenc libx264\n",
"\n",
"Enabled hwaccels:\n",
"av1_nvdec mpeg1_nvdec vp8_nvdec\n",
"h264_nvdec mpeg2_nvdec vp9_nvdec\n",
"hevc_nvdec mpeg4_nvdec wmv3_nvdec\n",
"mjpeg_nvdec vc1_nvdec\n",
"\n",
"Enabled parsers:\n",
"h263 mpeg4video vp9\n",
"\n",
"Enabled demuxers:\n",
"mov\n",
"\n",
"Enabled muxers:\n",
"mov mp4\n",
"\n",
"Enabled protocols:\n",
"file tcp\n",
"https tls\n",
"\n",
"Enabled filters:\n",
"aformat hflip transpose\n",
"anull null trim\n",
"atrim scale vflip\n",
"format testsrc2\n",
"\n",
"Enabled bsfs:\n",
"aac_adtstoasc null vp9_superframe_split\n",
"h264_mp4toannexb vp9_superframe\n",
"\n",
"Enabled indevs:\n",
"lavfi\n",
"\n",
"Enabled outdevs:\n",
"\n",
"License: nonfree and unredistributable\n"
]
}
],
"outputs": [],
"source": [
"# NOTE:\n",
"# When the configure script of FFmpeg 4 checks nvcc, it uses compute\n",
"# capability of 30 (3.0) by default. CUDA 11, however, does not support \n",
"# compute capability 30.\n",
"# Here, we use 37, which is supported by CUDA 11 and both K80 and T4.\n",
"#\n",
"# Tesla K80: 37\n",
"# NVIDIA T4: 75\n",
"\n",
"%env ccap=37\n",
"\n",
"# NOTE:\n",
"# We disable most of the features to speed up compilation\n",
"# The necessary components are\n",
"# - demuxer: mov, aac\n",
"# - decoder: h264, h264_nvdec\n",
"# - muxer: mp4\n",
"# - encoder: libx264, h264_nvenc\n",
"# - gnutls (HTTPS)\n",
"#\n",
"# Additionally, we use FFmpeg's virtual input device to generate \n",
"# test video data. This requires\n",
"# - input device: lavfi\n",
"# - filter: testsrc2\n",
"# - decoder: rawvideo\n",
"#\n",
"\n",
"!cd ffmpeg && ./configure \\\n",
" --prefix='/usr/' \\\n",
" --extra-cflags='-I/usr/local/cuda/include' \\\n",
" --extra-ldflags='-L/usr/local/cuda/lib64' \\\n",
" --nvccflags=\"-gencode arch=compute_${ccap},code=sm_${ccap} -O2\" \\\n",
" --disable-doc \\\n",
" --disable-static \\\n",
" --disable-bsfs \\\n",
" --disable-decoders \\\n",
" --disable-encoders \\\n",
" --disable-filters \\\n",
" --disable-demuxers \\\n",
" --disable-devices \\\n",
" --disable-muxers \\\n",
" --disable-parsers \\\n",
" --disable-postproc \\\n",
" --disable-protocols \\\n",
" --enable-decoder=aac \\\n",
" --enable-decoder=h264 \\\n",
" --enable-decoder=h264_cuvid \\\n",
" --enable-decoder=rawvideo \\\n",
" --enable-indev=lavfi \\\n",
" --enable-encoder=libx264 \\\n",
" --enable-encoder=h264_nvenc \\\n",
" --enable-demuxer=mov \\\n",
" --enable-muxer=mp4 \\\n",
" --enable-filter=scale \\\n",
" --enable-filter=testsrc2 \\\n",
" --enable-protocol=file \\\n",
" --enable-protocol=https \\\n",
" --enable-gnutls \\\n",
" --enable-shared \\\n",
" --enable-gpl \\\n",
" --enable-nonfree \\\n",
" --enable-cuda-nvcc \\\n",
" --enable-libx264 \\\n",
" --enable-nvenc \\\n",
" --enable-cuvid \\\n",
" --enable-nvdec"
"!wget -q -O input.mp4 \"https://download.pytorch.org/torchaudio/tutorial-assets/stream-api/NASAs_Most_Scientifically_Complex_Space_Observatory_Requires_Precision-MP4_small.mp4\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "MFTCT16ufL-e"
"id": "08XIDshiiFp-"
},
"source": [
"### Build and install FFmpeg"
"## Check the available GPU"
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Ki9PN3V8XbSh",
"outputId": "47b40f5f-ec63-4827-fdac-a7e17f6eb1d8"
"id": "gCegZlbgutNM",
"outputId": "7415cdd3-d8e8-476d-da13-27fa87267497"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"INSTALL\tlibavdevice/libavdevice.so\n",
"INSTALL\tlibavfilter/libavfilter.so\n",
"INSTALL\tlibavformat/libavformat.so\n",
"INSTALL\tlibavcodec/libavcodec.so\n",
"INSTALL\tlibswresample/libswresample.so\n",
"INSTALL\tlibswscale/libswscale.so\n",
"INSTALL\tlibavutil/libavutil.so\n",
"INSTALL\tinstall-progs-yes\n",
"INSTALL\tffmpeg\n",
"INSTALL\tffprobe\n"
"Thu Feb 9 15:54:05 2023 \n",
"+-----------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 510.47.03 Driver Version: 510.47.03 CUDA Version: 11.6 |\n",
"|-------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|===============================+======================+======================|\n",
"| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n",
"| N/A 58C P0 28W / 70W | 0MiB / 15360MiB | 0% Default |\n",
"| | | N/A |\n",
"+-------------------------------+----------------------+----------------------+\n",
" \n",
"+-----------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=============================================================================|\n",
"| No running processes found |\n",
"+-----------------------------------------------------------------------------+\n"
]
}
],
"source": [
"!cd ffmpeg && make clean && make -j > /dev/null 2>&1\n",
"!cd ffmpeg && make install"
"!nvidia-smi"
]
},
{
......@@ -555,50 +193,60 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 55,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4fu9POO7kbQL",
"outputId": "e55f7443-3a7f-471c-c894-5677fd843ee7"
"outputId": "3514bcc9-17e7-47a2-bb7e-a8162ccb1eb4"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
" VFS..D h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10\n",
" V..... h264_cuvid Nvidia CUVID H264 decoder (codec h264)\n"
" V..... h264_cuvid Nvidia CUVID H264 decoder (codec h264)\n",
" V..... hevc_cuvid Nvidia CUVID HEVC decoder (codec hevc)\n",
" V..... mjpeg_cuvid Nvidia CUVID MJPEG decoder (codec mjpeg)\n",
" V..... mpeg1_cuvid Nvidia CUVID MPEG1VIDEO decoder (codec mpeg1video)\n",
" V..... mpeg2_cuvid Nvidia CUVID MPEG2VIDEO decoder (codec mpeg2video)\n",
" V..... mpeg4_cuvid Nvidia CUVID MPEG4 decoder (codec mpeg4)\n",
" V..... vc1_cuvid Nvidia CUVID VC1 decoder (codec vc1)\n",
" V..... vp8_cuvid Nvidia CUVID VP8 decoder (codec vp8)\n",
" V..... vp9_cuvid Nvidia CUVID VP9 decoder (codec vp9)\n"
]
}
],
"source": [
"!ffprobe -hide_banner -decoders | grep h264"
"!ffmpeg -hide_banner -decoders | grep -i cuvid"
]
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 56,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "499UCyKtFPrO",
"outputId": "2cd0f6a5-cde9-42b7-c30b-95c920a44720"
"outputId": "06fe7564-5a17-453c-efbf-b04136652586"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
" V..... libx264 libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)\n",
" V....D h264_nvenc NVIDIA NVENC H.264 encoder (codec h264)\n"
" V..... h264_nvenc NVIDIA NVENC H.264 encoder (codec h264)\n",
" V..... nvenc NVIDIA NVENC H.264 encoder (codec h264)\n",
" V..... nvenc_h264 NVIDIA NVENC H.264 encoder (codec h264)\n",
" V..... nvenc_hevc NVIDIA NVENC hevc encoder (codec hevc)\n",
" V..... hevc_nvenc NVIDIA NVENC hevc encoder (codec hevc)\n"
]
}
],
"source": [
"!ffmpeg -hide_banner -encoders | grep 264"
"!ffmpeg -hide_banner -encoders | grep -i nvenc"
]
},
{
......@@ -612,13 +260,13 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 5,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "A--jYQBrfcOr",
"outputId": "f7f32af2-845d-4326-c9a7-6f3e05ca7231"
"outputId": "ba32eea4-52c5-4864-e7ba-45d2200b43ed"
},
"outputs": [
{
......@@ -632,14 +280,12 @@
" compatible_brands: mp42iso2avc1mp41\n",
" encoder : Lavf58.76.100\n",
" Duration: 00:03:26.04, start: 0.000000, bitrate: 1294 kb/s\n",
" Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 960x540 [SAR 1:1 DAR 16:9], 1156 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)\n",
" Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 960x540 [SAR 1:1 DAR 16:9], 1156 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)\n",
" Metadata:\n",
" handler_name : ?Mainconcept Video Media Handler\n",
" vendor_id : [0][0][0][0]\n",
" Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)\n",
" Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)\n",
" Metadata:\n",
" handler_name : #Mainconcept MP4 Sound Media Handler\n",
" vendor_id : [0][0][0][0]\n",
"Stream mapping:\n",
" Stream #0:0 -> #0:0 (h264 (h264_cuvid) -> h264 (h264_nvenc))\n",
" Stream #0:1 -> #0:1 (copy)\n",
......@@ -649,20 +295,18 @@
" major_brand : mp42\n",
" minor_version : 512\n",
" compatible_brands: mp42iso2avc1mp41\n",
" encoder : Lavf58.76.100\n",
" Stream #0:0(eng): Video: h264 (Main) (avc1 / 0x31637661), cuda(tv, bt709, progressive), 360x240 [SAR 1:1 DAR 3:2], q=2-31, 5000 kb/s, 29.97 fps, 30k tbn (default)\n",
" encoder : Lavf58.29.100\n",
" Stream #0:0(eng): Video: h264 (h264_nvenc) (Main) (avc1 / 0x31637661), cuda, 360x240 [SAR 1:1 DAR 3:2], q=-1--1, 5000 kb/s, 29.97 fps, 30k tbn, 29.97 tbc (default)\n",
" Metadata:\n",
" handler_name : ?Mainconcept Video Media Handler\n",
" vendor_id : [0][0][0][0]\n",
" encoder : Lavc58.134.100 h264_nvenc\n",
" encoder : Lavc58.54.100 h264_nvenc\n",
" Side data:\n",
" cpb: bitrate max/min/avg: 0/0/5000000 buffer size: 10000000 vbv_delay: N/A\n",
" Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)\n",
" cpb: bitrate max/min/avg: 0/0/5000000 buffer size: 10000000 vbv_delay: -1\n",
" Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)\n",
" Metadata:\n",
" handler_name : #Mainconcept MP4 Sound Media Handler\n",
" vendor_id : [0][0][0][0]\n",
"frame= 6175 fps=1712 q=11.0 Lsize= 37935kB time=00:03:26.01 bitrate=1508.5kbits/s speed=57.1x \n",
"video:34502kB audio:3234kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.526932%\n"
"frame= 6175 fps=1673 q=8.0 Lsize= 41278kB time=00:03:26.17 bitrate=1640.1kbits/s speed=55.9x \n",
"video:37869kB audio:3234kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.424815%\n"
]
}
],
......@@ -672,36 +316,30 @@
},
{
"cell_type": "markdown",
"metadata": {
"id": "UYzJWphMG9nh"
},
"source": [
"## Benchmarking GPU Encoding and Decoding\n",
"\n",
"Now that FFmpeg and the resulting libraries are ready to use, we test NVDEC/NVENC with TorchAudio. For the basics of TorchAudio's streaming APIs, please refer to [Media I/O tutorials](https://pytorch.org/audio/main/tutorials.io.html).\n",
"\n",
"**Note**\n",
"\n",
"If you rebuild FFmpeg after importing torchaudio, you'll need to restart the session to activate the newly built FFmpeg libraries."
]
"## Check the TorchAudio / FFmpeg integration"
],
"metadata": {
"id": "YV-gmE6o6pRi"
}
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 6,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "wDJ-qdM45fV6",
"outputId": "9242a9bd-62e8-4217-8113-a18a62fbbe94"
"outputId": "3cd9990b-a910-4428-ad3b-408bb69d0808"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"1.13.0.dev20221006+cu116\n",
"0.13.0.dev20221006+cu116\n"
"2.0.0.dev20230209+cu117\n",
"2.0.0.dev20230208+cu117\n"
]
}
],
......@@ -717,7 +355,60 @@
},
{
"cell_type": "code",
"execution_count": 12,
"source": [
"from torchaudio.utils import ffmpeg_utils\n",
"\n",
"print(\"Library versions:\")\n",
"print(ffmpeg_utils.get_versions())\n",
"print(\"\\nBuild config:\")\n",
"print(ffmpeg_utils.get_build_config())\n",
"print(\"\\nDecoders:\")\n",
"print([k for k in ffmpeg_utils.get_video_decoders().keys() if \"cuvid\" in k])\n",
"print(\"\\nEncoders:\")\n",
"print([k for k in ffmpeg_utils.get_video_encoders().keys() if \"nvenc\" in k])"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6hBVOJuo6yWQ",
"outputId": "559d6dd9-39f8-4fc2-c00f-1500f277b596"
},
"execution_count": 61,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Library versions:\n",
"{'libavutil': (56, 31, 100), 'libavcodec': (58, 54, 100), 'libavformat': (58, 29, 100), 'libavfilter': (7, 57, 100), 'libavdevice': (58, 8, 100)}\n",
"\n",
"Build config:\n",
"--prefix=/usr --extra-version=0ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared\n",
"\n",
"Decoders:\n",
"['h264_cuvid', 'hevc_cuvid', 'mjpeg_cuvid', 'mpeg1_cuvid', 'mpeg2_cuvid', 'mpeg4_cuvid', 'vc1_cuvid', 'vp8_cuvid', 'vp9_cuvid']\n",
"\n",
"Encoders:\n",
"['h264_nvenc', 'nvenc', 'nvenc_h264', 'nvenc_hevc', 'hevc_nvenc']\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "UYzJWphMG9nh"
},
"source": [
"## Benchmarking GPU Encoding and Decoding\n",
"\n",
"Now that FFmpeg and the resulting libraries are ready to use, we test NVDEC/NVENC with TorchAudio. For the basics of TorchAudio's streaming APIs, please refer to [Media I/O tutorials](https://pytorch.org/audio/main/tutorials.io.html)."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"id": "zKMACIJNIXns"
},
......@@ -744,65 +435,20 @@
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lbA3S6p_Z2lI",
"outputId": "818e6aef-048a-49d3-a29b-1e3f421dc8ef"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Collecting boto3\n",
" Downloading boto3-1.24.88-py3-none-any.whl (132 kB)\n",
"\u001b[?25l\n",
"\u001b[?25hCollecting s3transfer<0.7.0,>=0.6.0\n",
" Downloading s3transfer-0.6.0-py3-none-any.whl (79 kB)\n",
"\u001b[?25l\n",
"\u001b[?25hCollecting jmespath<2.0.0,>=0.7.1\n",
" Downloading jmespath-1.0.1-py3-none-any.whl (20 kB)\n",
"Collecting botocore<1.28.0,>=1.27.88\n",
" Downloading botocore-1.27.88-py3-none-any.whl (9.2 MB)\n",
"\u001b[?25l\n",
"\u001b[?25hCollecting urllib3<1.27,>=1.25.4\n",
" Downloading urllib3-1.26.12-py2.py3-none-any.whl (140 kB)\n",
"\u001b[?25l\n",
"\u001b[?25hRequirement already satisfied: python-dateutil<3.0.0,>=2.1 in /usr/local/lib/python3.7/dist-packages (from botocore<1.28.0,>=1.27.88->boto3) (2.8.2)\n",
"Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.28.0,>=1.27.88->boto3) (1.15.0)\n",
"Installing collected packages: urllib3, jmespath, botocore, s3transfer, boto3\n",
" Attempting uninstall: urllib3\n",
" Found existing installation: urllib3 1.24.3\n",
" Uninstalling urllib3-1.24.3:\n",
" Successfully uninstalled urllib3-1.24.3\n",
"Successfully installed boto3-1.24.88 botocore-1.27.88 jmespath-1.0.1 s3transfer-0.6.0 urllib3-1.26.12\n"
]
}
],
"source": [
"!pip3 install --progress-bar off boto3 2> /dev/null"
]
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 9,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "g3TMksRk5ara",
"outputId": "17191485-7188-4986-e540-c77df1c5afe0"
"outputId": "98830754-dbe1-4246-9fc6-e4016b382a89"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"1.24.88\n"
"1.26.67\n"
]
}
],
......@@ -814,17 +460,6 @@
"print(boto3.__version__)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"id": "d0GYPyGGTz-q"
},
"outputs": [],
"source": [
"!wget -q -O input.mp4 \"https://download.pytorch.org/torchaudio/tutorial-assets/stream-api/NASAs_Most_Scientifically_Complex_Space_Observatory_Requires_Precision-MP4_small.mp4\""
]
},
{
"cell_type": "markdown",
"metadata": {
......@@ -838,7 +473,7 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 11,
"metadata": {
"id": "GsmoRAY75T6J"
},
......@@ -854,10 +489,10 @@
" print(\"* Source:\", src)\n",
" print(\"=\" * 40)\n",
"\n",
" t0 = time.monotonic()\n",
" s = StreamReader(src)\n",
" s.add_video_stream(5, **config)\n",
"\n",
" t0 = time.monotonic()\n",
" num_frames = 0\n",
" for i, (chunk, ) in enumerate(s.stream()):\n",
" if i == 0:\n",
......@@ -888,7 +523,7 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 12,
"metadata": {
"id": "mlrA9oVM3qvt"
},
......@@ -910,13 +545,13 @@
},
{
"cell_type": "code",
"execution_count": 18,
"execution_count": 13,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "z6kivDretHtS",
"outputId": "fc14c8a1-6f26-4370-b532-d90098d0f775"
"outputId": "6ac2d3d4-3526-4946-bb47-a9016b253ba2"
},
"outputs": [
{
......@@ -930,7 +565,7 @@
" - Chunk: torch.Size([5, 3, 540, 960]) cpu torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 46.691246449000005 seconds.\n",
" - Elapsed: 43.65067997 seconds.\n",
"\n"
]
}
......@@ -945,7 +580,7 @@
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 14,
"metadata": {
"id": "vAEDVY0D37bJ"
},
......@@ -966,13 +601,13 @@
},
{
"cell_type": "code",
"execution_count": 20,
"execution_count": 15,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "V6jwiJD-tW0M",
"outputId": "0f40c5b2-5e04-4ca1-9902-5a9ed9dc5820"
"outputId": "62d36f34-969b-42fb-f961-7b2a525a0dd1"
},
"outputs": [
{
......@@ -986,7 +621,7 @@
" - Chunk: torch.Size([5, 3, 540, 960]) cuda:0 torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 6.117441406000012 seconds.\n",
" - Elapsed: 5.754925530000008 seconds.\n",
"\n"
]
}
......@@ -1002,7 +637,7 @@
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 16,
"metadata": {
"id": "yIA6UAaw39VC"
},
......@@ -1025,7 +660,7 @@
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": 17,
"metadata": {
"id": "ICa21rL84QVb"
},
......@@ -1046,13 +681,13 @@
},
{
"cell_type": "code",
"execution_count": 23,
"execution_count": 18,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6AGfH8X8tboy",
"outputId": "3039e4b6-35a2-4b55-e7a7-d8b1b63e84f6"
"outputId": "54a6bfee-cf08-430b-cd7a-b07f3056974a"
},
"outputs": [
{
......@@ -1066,7 +701,7 @@
" - Chunk: torch.Size([5, 3, 540, 960]) cpu torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 46.460909987000036 seconds.\n",
" - Elapsed: 33.74701378400002 seconds.\n",
"\n"
]
}
......@@ -1077,7 +712,7 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 19,
"metadata": {
"id": "4u8glKk14bYT"
},
......@@ -1098,13 +733,13 @@
},
{
"cell_type": "code",
"execution_count": 25,
"execution_count": 20,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "95bky0TqtfMI",
"outputId": "14e2cea4-fe27-405b-feec-e276c466542a"
"outputId": "99d1c9c6-6034-4cda-a4a6-47973e7517cf"
},
"outputs": [
{
......@@ -1118,7 +753,7 @@
" - Chunk: torch.Size([5, 3, 540, 960]) cuda:0 torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 4.23164078800005 seconds.\n",
" - Elapsed: 15.769149663000007 seconds.\n",
"\n"
]
}
......@@ -1129,7 +764,7 @@
},
{
"cell_type": "code",
"execution_count": 26,
"execution_count": 21,
"metadata": {
"id": "kir92rPk4eLr"
},
......@@ -1152,7 +787,7 @@
},
{
"cell_type": "code",
"execution_count": 27,
"execution_count": 22,
"metadata": {
"id": "XBYc5AiGORUU"
},
......@@ -1185,7 +820,7 @@
},
{
"cell_type": "code",
"execution_count": 28,
"execution_count": 23,
"metadata": {
"id": "Odq5pMJ4M2ph"
},
......@@ -1215,13 +850,13 @@
},
{
"cell_type": "code",
"execution_count": 29,
"execution_count": 24,
"metadata": {
"id": "rjDH0g0qOAhh",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "e8323115-a3f6-4525-9645-e20d77fadc95"
"outputId": "d7c303bb-4a40-4259-f4ef-b967027590e1"
},
"outputs": [
{
......@@ -1230,12 +865,12 @@
"text": [
"========================================\n",
"* Configuration: {'decoder': 'h264'}\n",
"* Source: <botocore.response.StreamingBody object at 0x7fb991dddfd0>\n",
"* Source: <botocore.response.StreamingBody object at 0x7fcc9b0b83a0>\n",
"========================================\n",
" - Chunk: torch.Size([5, 3, 540, 960]) cpu torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 40.758733775999985 seconds.\n",
" - Elapsed: 29.465254898000012 seconds.\n",
"\n"
]
}
......@@ -1248,7 +883,7 @@
},
{
"cell_type": "code",
"execution_count": 30,
"execution_count": 25,
"metadata": {
"id": "JfjvXqBqQGyu"
},
......@@ -1269,13 +904,13 @@
},
{
"cell_type": "code",
"execution_count": 31,
"execution_count": 26,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "17-0MVlZOm-f",
"outputId": "9604cb57-cdb1-4e72-8754-47dfa737f0f7"
"outputId": "36891a0f-8fa2-4b99-b27a-4ac93fa19588"
},
"outputs": [
{
......@@ -1284,12 +919,12 @@
"text": [
"========================================\n",
"* Configuration: {'decoder': 'h264_cuvid', 'hw_accel': 'cuda:0'}\n",
"* Source: <botocore.response.StreamingBody object at 0x7fb991d390d0>\n",
"* Source: <botocore.response.StreamingBody object at 0x7fcc9b0b8730>\n",
"========================================\n",
" - Chunk: torch.Size([5, 3, 540, 960]) cuda:0 torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 4.620101478000038 seconds.\n",
" - Elapsed: 3.475249672000018 seconds.\n",
"\n"
]
}
......@@ -1302,7 +937,7 @@
},
{
"cell_type": "code",
"execution_count": 32,
"execution_count": 27,
"metadata": {
"id": "VpDLx494QIN4"
},
......@@ -1325,7 +960,7 @@
},
{
"cell_type": "code",
"execution_count": 33,
"execution_count": 28,
"metadata": {
"id": "XKpuH_tXvMSF"
},
......@@ -1345,13 +980,13 @@
},
{
"cell_type": "code",
"execution_count": 34,
"execution_count": 29,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "OEtAVQVYwVCy",
"outputId": "29fd9dca-5378-48a3-9ef3-26ab1b892107"
"outputId": "ddb62460-d669-4afb-86d9-1c33d8c4be08"
},
"outputs": [
{
......@@ -1365,7 +1000,7 @@
" - Chunk: torch.Size([5, 3, 240, 360]) cpu torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 19.082725973000038 seconds.\n",
" - Elapsed: 17.26762169899996 seconds.\n",
"\n"
]
}
......@@ -1381,7 +1016,7 @@
},
{
"cell_type": "code",
"execution_count": 35,
"execution_count": 30,
"metadata": {
"id": "uzZMz0rW4j73"
},
......@@ -1402,13 +1037,13 @@
},
{
"cell_type": "code",
"execution_count": 36,
"execution_count": 31,
"metadata": {
"id": "XajhZb-G4mwm",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "29038cfd-2d4e-4b4b-a40f-ef6731ddff96"
"outputId": "aafb9dc0-4dcf-4c37-c7f7-840e832f5aeb"
},
"outputs": [
{
......@@ -1422,7 +1057,7 @@
" - Chunk: torch.Size([5, 3, 240, 360]) cuda:0 torch.uint8\n",
"\n",
" - Processed 6175 frames.\n",
" - Elapsed: 4.157032522999998 seconds.\n",
" - Elapsed: 15.233130482000035 seconds.\n",
"\n"
]
}
......@@ -1441,7 +1076,7 @@
},
{
"cell_type": "code",
"execution_count": 37,
"execution_count": 32,
"metadata": {
"id": "5mXoy38TwYVx"
},
......@@ -1465,24 +1100,24 @@
},
{
"cell_type": "code",
"execution_count": 38,
"execution_count": 33,
"metadata": {
"id": "Ni0bihmogZAb",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "b586825a-1164-4b9e-f5ca-79febf95628a"
"outputId": "ad15bfbb-f153-42b5-f207-bfd35f1f51bd"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
" CPU NVDEC\n",
"Decoding (local file) 46.691246 6.117441\n",
"Decoding (network file) 46.460911 4.231641\n",
"Decoding (file-like object, S3) 40.758736 4.620101\n",
"Decoding + Resize 19.082726 4.157032\n"
" CPU NVDEC\n",
"Decoding (local file) 43.650681 5.754926\n",
"Decoding (network file) 33.747013 15.769150\n",
"Decoding (file-like object, S3) 29.465256 3.475250\n",
"Decoding + Resize 17.267622 15.233130\n"
]
}
],
......@@ -1506,7 +1141,7 @@
},
{
"cell_type": "code",
"execution_count": 39,
"execution_count": 34,
"metadata": {
"id": "nWTT5ih5v1s6"
},
......@@ -1533,14 +1168,14 @@
},
{
"cell_type": "code",
"execution_count": 40,
"execution_count": 35,
"metadata": {
"id": "5AL9u6_xmRQa",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"outputId": "89bdea08-4d2c-4192-874c-6e1b316ea63a"
"outputId": "a717d7b4-9d30-4dd8-879e-d06722e0b4a3"
},
"outputs": [
{
......@@ -1551,7 +1186,7 @@
]
},
"metadata": {},
"execution_count": 40
"execution_count": 35
},
{
"output_type": "display_data",
......@@ -1590,7 +1225,7 @@
},
{
"cell_type": "code",
"execution_count": 41,
"execution_count": 36,
"metadata": {
"id": "k5WkyQEp0hjv"
},
......@@ -1602,10 +1237,9 @@
" print(\"* Destination:\", dst)\n",
" print(\"=\" * 40)\n",
"\n",
" t0 = time.monotonic()\n",
" s = StreamWriter(dst)\n",
" s.add_video_stream(**config)\n",
"\n",
" t0 = time.monotonic()\n",
" with s.open():\n",
" s.write_video_chunk(0, data)\n",
" elapsed = time.monotonic() - t0\n",
......@@ -1630,7 +1264,7 @@
},
{
"cell_type": "code",
"execution_count": 42,
"execution_count": 37,
"metadata": {
"id": "nHynkI-oK9mX"
},
......@@ -1658,7 +1292,7 @@
},
{
"cell_type": "code",
"execution_count": 43,
"execution_count": 38,
"metadata": {
"id": "2dZk8Ui7EZew"
},
......@@ -1685,13 +1319,13 @@
},
{
"cell_type": "code",
"execution_count": 44,
"execution_count": 39,
"metadata": {
"id": "wP648bHCH9p_",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "30af3ebc-a27c-4c40-a533-b4ac8e977527"
"outputId": "7186edac-47de-4bf3-aee4-972be5587aab"
},
"outputs": [
{
......@@ -1704,7 +1338,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 3.280829835000077 seconds.\n",
" - Elapsed: 6.311792093000008 seconds.\n",
"\n"
]
}
......@@ -1731,13 +1365,13 @@
},
{
"cell_type": "code",
"execution_count": 45,
"execution_count": 40,
"metadata": {
"id": "zQ9W_UVTIf-E",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "3a9ccbfb-d243-4f1f-a790-0595a1de8bba"
"outputId": "535e49f3-ba72-4ef9-aa53-006bccee4f0d"
},
"outputs": [
{
......@@ -1750,7 +1384,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 0.34294435300000714 seconds.\n",
" - Elapsed: 0.5352325430000064 seconds.\n",
"\n"
]
}
......@@ -1778,13 +1412,13 @@
},
{
"cell_type": "code",
"execution_count": 46,
"execution_count": 41,
"metadata": {
"id": "EHjyMYpJnEb3",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "b3a4c529-9b6e-468e-a836-6e5f5fe51d56"
"outputId": "2138a71c-7e9f-4571-d076-4ef44a1ea02c"
},
"outputs": [
{
......@@ -1797,7 +1431,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 0.2424524550000342 seconds.\n",
" - Elapsed: 0.7045466739999711 seconds.\n",
"\n"
]
}
......@@ -1828,7 +1462,7 @@
},
{
"cell_type": "code",
"execution_count": 47,
"execution_count": 42,
"metadata": {
"id": "CUdzN9BzJlo_"
},
......@@ -1855,13 +1489,13 @@
},
{
"cell_type": "code",
"execution_count": 48,
"execution_count": 43,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "FoEM76wFJta5",
"outputId": "abe666de-8d02-469a-beea-74fcff494b89"
"outputId": "25c88435-06d8-4383-ccfa-a747dc246e46"
},
"outputs": [
{
......@@ -1874,7 +1508,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 11.638768525999922 seconds.\n",
" - Elapsed: 14.017578084000036 seconds.\n",
"\n"
]
}
......@@ -1899,13 +1533,13 @@
},
{
"cell_type": "code",
"execution_count": 49,
"execution_count": 44,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fgNR79olJ7Yo",
"outputId": "65484cc4-ab54-4373-b1a4-50bfea20e73d"
"outputId": "9bbbacb6-a3d5-485a-9194-26efc9fe6f1e"
},
"outputs": [
{
......@@ -1918,7 +1552,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 0.8508033889999069 seconds.\n",
" - Elapsed: 0.9797491379999883 seconds.\n",
"\n"
]
}
......@@ -1943,13 +1577,13 @@
},
{
"cell_type": "code",
"execution_count": 50,
"execution_count": 45,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2NX4SU5xJ7zc",
"outputId": "130ad5a6-a197-46dc-d799-d230e2b469c0"
"outputId": "c81cc029-e6e0-4552-d3a0-cb5ba20935c8"
},
"outputs": [
{
......@@ -1962,7 +1596,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 0.6384492569999338 seconds.\n",
" - Elapsed: 0.7259890020000057 seconds.\n",
"\n"
]
}
......@@ -2006,7 +1640,7 @@
"metadata": {
"id": "klcLfXipO5OX"
},
"execution_count": 51,
"execution_count": 46,
"outputs": []
},
{
......@@ -2033,9 +1667,9 @@
"base_uri": "https://localhost:8080/"
},
"id": "6UuiAEowOedt",
"outputId": "2bcc2c9b-dc27-4dd5-b469-44e760a0068a"
"outputId": "06584da3-d1d4-4cd4-f96f-ea002a2361b6"
},
"execution_count": 52,
"execution_count": 47,
"outputs": [
{
"output_type": "stream",
......@@ -2047,7 +1681,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 27.020421489 seconds.\n",
" - Elapsed: 29.441768007999997 seconds.\n",
"\n"
]
}
......@@ -2077,9 +1711,9 @@
"base_uri": "https://localhost:8080/"
},
"id": "dzYNn8HtOeVi",
"outputId": "53b8e871-360f-483a-c7d6-c217a913dae9"
"outputId": "47a24824-e3a3-4426-9b6d-414438c7a8d4"
},
"execution_count": 53,
"execution_count": 48,
"outputs": [
{
"output_type": "stream",
......@@ -2091,7 +1725,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 1.60377999800005 seconds.\n",
" - Elapsed: 1.5768605540000067 seconds.\n",
"\n"
]
}
......@@ -2125,9 +1759,9 @@
"base_uri": "https://localhost:8080/"
},
"id": "cUZOWVllOeRl",
"outputId": "b7608edc-ed60-4bc9-ab44-fa0b333a4264"
"outputId": "a0cbae4c-376d-4a8e-f12b-625432ae634f"
},
"execution_count": 54,
"execution_count": 49,
"outputs": [
{
"output_type": "stream",
......@@ -2139,7 +1773,7 @@
"========================================\n",
"\n",
" - Processed 450 frames.\n",
" - Elapsed: 1.4101193979998925 seconds.\n",
" - Elapsed: 1.4002963130000126 seconds.\n",
"\n"
]
}
......@@ -2173,18 +1807,18 @@
"base_uri": "https://localhost:8080/"
},
"id": "jDWUQFjVPaUV",
"outputId": "eda3af22-a346-4e0a-fd48-f1227e524ddf"
"outputId": "00409409-bb44-4d54-c381-589c631a6c12"
},
"execution_count": 55,
"execution_count": 50,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
" 360P 720P 1080P\n",
"CPU 3.280830 11.638768 27.020422\n",
"CUDA (from CPU Tensor) 0.342944 0.850803 1.603780\n",
"CUDA (from CUDA Tensor) 0.242452 0.638449 1.410119\n"
"CPU 6.311792 14.017578 29.441769\n",
"CUDA (from CPU Tensor) 0.535233 0.979749 1.576861\n",
"CUDA (from CUDA Tensor) 0.704547 0.725989 1.400296\n"
]
}
]
......@@ -2203,9 +1837,9 @@
"height": 265
},
"id": "gEccR5zwTYRQ",
"outputId": "486af2b2-9137-4197-bc6b-b17af0b2075a"
"outputId": "5f0f71e7-6336-416d-9b53-5653d05ef23f"
},
"execution_count": 56,
"execution_count": 51,
"outputs": [
{
"output_type": "display_data",
......@@ -2213,7 +1847,7 @@
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
],
"image/png": "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\n"
"image/png": "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\n"
},
"metadata": {
"needs_background": "light"
......@@ -2252,12 +1886,12 @@
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 431
"height": 224
},
"id": "LNPWCXxOgnqz",
"outputId": "cd9449d8-d464-4c0e-88c3-e71d7b3261e5"
"outputId": "72aec5f1-3c46-4294-f330-fb0f92e65e94"
},
"execution_count": 61,
"execution_count": 52,
"outputs": [
{
"output_type": "execute_result",
......@@ -2281,7 +1915,7 @@
]
},
"metadata": {},
"execution_count": 61
"execution_count": 52
}
]
},
......@@ -2300,11 +1934,6 @@
"metadata": {
"accelerator": "GPU",
"colab": {
"collapsed_sections": [
"VcKsO-zurtWM",
"PWT0m_LGq_GE",
"TpWDpxBvDy-b"
],
"provenance": [],
"toc_visible": true
},
......
......@@ -32,6 +32,7 @@ model implementations and application components.
build.linux
build.windows
build.jetson
build.ffmpeg
.. toctree::
:maxdepth: 1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment