Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Kamino666/09f878289e1e6dc13b0a3b2b508d68a5 to your computer and use it in GitHub Desktop.
Save Kamino666/09f878289e1e6dc13b0a3b2b508d68a5 to your computer and use it in GitHub Desktop.
针对Python中各种读取视频库的比较
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "dNF-t2FO1M6r"
},
"source": [
"# Benchmark of Video Reader in Python\n",
"\n",
"比较Python中的各种读取视频的实现\n",
"\n",
"This notebook compares several video reader in Python.\n",
"\n",
"1. OpenCV(cv2)\n",
"2. Decord\n",
"3. MMCV\n",
"4. pyAV"
]
},
{
"cell_type": "markdown",
"source": [
"安装一个新版本的ffmpeg"
],
"metadata": {
"id": "v3mbqj2_50BR"
}
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hDsdrVMS_YFX",
"outputId": "ad257ab8-daad-4b61-e9e7-bf58d2c3713c"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cloning into 'ffmpeg-colab'...\n",
"remote: Enumerating objects: 19, done.\u001b[K\n",
"remote: Counting objects: 100% (5/5), done.\u001b[K\n",
"remote: Compressing objects: 100% (5/5), done.\u001b[K\n",
"remote: Total 19 (delta 3), reused 0 (delta 0), pack-reused 14\u001b[K\n",
"Unpacking objects: 100% (19/19), done.\n",
"FFmpeg was found at /usr/bin/ffmpeg\n",
"Removing old FFmpeg\n",
"Done\n",
"Moving new ffmpeg to /usr/bin\n",
"FFmpeg was successfully installed\n"
]
}
],
"source": [
"!git clone https://github.com/XniceCraft/ffmpeg-colab.git\n",
"!sudo bash ./ffmpeg-colab/install"
]
},
{
"cell_type": "markdown",
"source": [
"安装各种库"
],
"metadata": {
"id": "wvM7RzXW5zU6"
}
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "zc3_BslhGo7k",
"outputId": "3f8237e7-036a-4eaf-8eae-607ececf2f2b"
},
"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 youtube-dl\n",
" Downloading youtube_dl-2021.12.17-py2.py3-none-any.whl (1.9 MB)\n",
"\u001b[K |████████████████████████████████| 1.9 MB 7.3 MB/s \n",
"\u001b[?25hInstalling collected packages: youtube-dl\n",
"Successfully installed youtube-dl-2021.12.17\n",
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Collecting memory_profiler\n",
" Downloading memory_profiler-0.60.0.tar.gz (38 kB)\n",
"Requirement already satisfied: psutil in /usr/local/lib/python3.7/dist-packages (from memory_profiler) (5.4.8)\n",
"Building wheels for collected packages: memory-profiler\n",
" Building wheel for memory-profiler (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
" Created wheel for memory-profiler: filename=memory_profiler-0.60.0-py3-none-any.whl size=31284 sha256=1da91e7a81ad45b33dbf0306f36d941dfc2ac8a7053756787e1292632a13ce6c\n",
" Stored in directory: /root/.cache/pip/wheels/67/2b/fb/326e30d638c538e69a5eb0aa47f4223d979f502bbdb403950f\n",
"Successfully built memory-profiler\n",
"Installing collected packages: memory-profiler\n",
"Successfully installed memory-profiler-0.60.0\n",
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Collecting mmcv\n",
" Downloading mmcv-1.6.1.tar.gz (563 kB)\n",
"\u001b[K |████████████████████████████████| 563 kB 7.2 MB/s \n",
"\u001b[?25hCollecting addict\n",
" Downloading addict-2.4.0-py3-none-any.whl (3.8 kB)\n",
"Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmcv) (1.21.6)\n",
"Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from mmcv) (21.3)\n",
"Requirement already satisfied: Pillow in /usr/local/lib/python3.7/dist-packages (from mmcv) (7.1.2)\n",
"Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from mmcv) (6.0)\n",
"Collecting yapf\n",
" Downloading yapf-0.32.0-py2.py3-none-any.whl (190 kB)\n",
"\u001b[K |████████████████████████████████| 190 kB 63.5 MB/s \n",
"\u001b[?25hRequirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /usr/local/lib/python3.7/dist-packages (from packaging->mmcv) (3.0.9)\n",
"Building wheels for collected packages: mmcv\n",
" Building wheel for mmcv (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
" Created wheel for mmcv: filename=mmcv-1.6.1-py2.py3-none-any.whl size=860296 sha256=9fc51c5967cfe708fa7b505cbbbbdfbc8508540ec00591aafc79f17ab0d34d1e\n",
" Stored in directory: /root/.cache/pip/wheels/e0/43/68/40160e8aa085d474903f0ad3764bac92e698936bfcf8a5454b\n",
"Successfully built mmcv\n",
"Installing collected packages: yapf, addict, mmcv\n",
"Successfully installed addict-2.4.0 mmcv-1.6.1 yapf-0.32.0\n",
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Collecting av\n",
" Downloading av-9.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (28.2 MB)\n",
"\u001b[K |████████████████████████████████| 28.2 MB 1.5 MB/s \n",
"\u001b[?25hInstalling collected packages: av\n",
"Successfully installed av-9.2.0\n"
]
}
],
"source": [
"!sudo -H pip install --upgrade youtube-dl\n",
"!pip install -U memory_profiler\n",
"# !pip install decord\n",
"!pip install mmcv\n",
"!pip install av"
]
},
{
"cell_type": "markdown",
"source": [
"安装GPU版本的Decord"
],
"metadata": {
"id": "1NGuLGJOWyuH"
}
},
{
"cell_type": "code",
"source": [
"!sudo apt-get update\n",
"!sudo apt-get install -y build-essential python3-dev python3-setuptools make cmake\n",
"!sudo apt-get install -y libavcodec-dev libavfilter-dev libavformat-dev libavutil-dev\n",
"!git clone --recursive https://github.com/dmlc/decord\n",
"%cd decord\n",
"!mkdir build\n",
"%cd build\n",
"!cmake .. -DUSE_CUDA=ON -DCMAKE_BUILD_TYPE=Release \n",
"!make\n",
"%cd /content/decord/python\n",
"!python setup.py install --user\n",
"%cd /content"
],
"metadata": {
"id": "OBEihCBlSbSF",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "f55a8ee4-5222-4f85-e4f8-5bfb6663f0d0"
},
"execution_count": 3,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"\r0% [Working]\r \rGet:1 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease [3,626 B]\n",
"\r0% [Connecting to archive.ubuntu.com (185.125.190.36)] [Connecting to security.\r0% [Connecting to archive.ubuntu.com (185.125.190.36)] [Connecting to security.\r0% [1 InRelease gpgv 3,626 B] [Connecting to archive.ubuntu.com (185.125.190.36\r \rIgn:2 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 InRelease\n",
"\r0% [1 InRelease gpgv 3,626 B] [Connecting to archive.ubuntu.com (185.125.190.36\r \rGet:3 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 InRelease [1,581 B]\n",
"Hit:4 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 Release\n",
"Get:5 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]\n",
"Get:6 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ Packages [91.1 kB]\n",
"Get:7 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Packages [912 kB]\n",
"Hit:8 http://archive.ubuntu.com/ubuntu bionic InRelease\n",
"Get:9 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease [15.9 kB]\n",
"Get:11 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]\n",
"Get:12 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [2,939 kB]\n",
"Hit:13 http://ppa.launchpad.net/cran/libgit2/ubuntu bionic InRelease\n",
"Get:14 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]\n",
"Hit:15 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease\n",
"Hit:16 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease\n",
"Get:17 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1,534 kB]\n",
"Get:18 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [2,311 kB]\n",
"Get:19 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main Sources [2,094 kB]\n",
"Get:20 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [3,369 kB]\n",
"Get:21 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main amd64 Packages [1,073 kB]\n",
"Fetched 14.6 MB in 4s (4,064 kB/s)\n",
"Reading package lists... Done\n",
"Reading package lists... Done\n",
"Building dependency tree \n",
"Reading state information... Done\n",
"build-essential is already the newest version (12.4ubuntu1).\n",
"make is already the newest version (4.1-9.1ubuntu1).\n",
"make set to manually installed.\n",
"cmake is already the newest version (3.10.2-1ubuntu2.18.04.2).\n",
"python3-dev is already the newest version (3.6.7-1~18.04).\n",
"python3-dev set to manually installed.\n",
"The following package was automatically installed and is no longer required:\n",
" libnvidia-common-460\n",
"Use 'sudo apt autoremove' to remove it.\n",
"The following additional packages will be installed:\n",
" python3-pkg-resources\n",
"Suggested packages:\n",
" python-setuptools-doc\n",
"The following NEW packages will be installed:\n",
" python3-pkg-resources python3-setuptools\n",
"0 upgraded, 2 newly installed, 0 to remove and 43 not upgraded.\n",
"Need to get 346 kB of archives.\n",
"After this operation, 1,848 kB of additional disk space will be used.\n",
"Get:1 http://archive.ubuntu.com/ubuntu bionic/main amd64 python3-pkg-resources all 39.0.1-2 [98.8 kB]\n",
"Get:2 http://archive.ubuntu.com/ubuntu bionic/main amd64 python3-setuptools all 39.0.1-2 [248 kB]\n",
"Fetched 346 kB in 1s (653 kB/s)\n",
"debconf: unable to initialize frontend: Dialog\n",
"debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76, <> line 2.)\n",
"debconf: falling back to frontend: Readline\n",
"debconf: unable to initialize frontend: Readline\n",
"debconf: (This frontend requires a controlling tty.)\n",
"debconf: falling back to frontend: Teletype\n",
"dpkg-preconfigure: unable to re-open stdin: \n",
"Selecting previously unselected package python3-pkg-resources.\n",
"(Reading database ... 155676 files and directories currently installed.)\n",
"Preparing to unpack .../python3-pkg-resources_39.0.1-2_all.deb ...\n",
"Unpacking python3-pkg-resources (39.0.1-2) ...\n",
"Selecting previously unselected package python3-setuptools.\n",
"Preparing to unpack .../python3-setuptools_39.0.1-2_all.deb ...\n",
"Unpacking python3-setuptools (39.0.1-2) ...\n",
"Setting up python3-pkg-resources (39.0.1-2) ...\n",
"Setting up python3-setuptools (39.0.1-2) ...\n",
"Reading package lists... Done\n",
"Building dependency tree \n",
"Reading state information... Done\n",
"libavcodec-dev is already the newest version (7:3.4.11-0ubuntu0.1).\n",
"libavcodec-dev set to manually installed.\n",
"libavformat-dev is already the newest version (7:3.4.11-0ubuntu0.1).\n",
"libavformat-dev set to manually installed.\n",
"libavutil-dev is already the newest version (7:3.4.11-0ubuntu0.1).\n",
"libavutil-dev set to manually installed.\n",
"The following package was automatically installed and is no longer required:\n",
" libnvidia-common-460\n",
"Use 'sudo apt autoremove' to remove it.\n",
"The following additional packages will be installed:\n",
" libpostproc-dev\n",
"The following NEW packages will be installed:\n",
" libavfilter-dev libpostproc-dev\n",
"0 upgraded, 2 newly installed, 0 to remove and 43 not upgraded.\n",
"Need to get 1,067 kB of archives.\n",
"After this operation, 5,019 kB of additional disk space will be used.\n",
"Get:1 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 libpostproc-dev amd64 7:3.4.11-0ubuntu0.1 [51.0 kB]\n",
"Get:2 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 libavfilter-dev amd64 7:3.4.11-0ubuntu0.1 [1,016 kB]\n",
"Fetched 1,067 kB in 1s (1,714 kB/s)\n",
"debconf: unable to initialize frontend: Dialog\n",
"debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76, <> line 2.)\n",
"debconf: falling back to frontend: Readline\n",
"debconf: unable to initialize frontend: Readline\n",
"debconf: (This frontend requires a controlling tty.)\n",
"debconf: falling back to frontend: Teletype\n",
"dpkg-preconfigure: unable to re-open stdin: \n",
"Selecting previously unselected package libpostproc-dev:amd64.\n",
"(Reading database ... 155789 files and directories currently installed.)\n",
"Preparing to unpack .../libpostproc-dev_7%3a3.4.11-0ubuntu0.1_amd64.deb ...\n",
"Unpacking libpostproc-dev:amd64 (7:3.4.11-0ubuntu0.1) ...\n",
"Selecting previously unselected package libavfilter-dev:amd64.\n",
"Preparing to unpack .../libavfilter-dev_7%3a3.4.11-0ubuntu0.1_amd64.deb ...\n",
"Unpacking libavfilter-dev:amd64 (7:3.4.11-0ubuntu0.1) ...\n",
"Setting up libpostproc-dev:amd64 (7:3.4.11-0ubuntu0.1) ...\n",
"Setting up libavfilter-dev:amd64 (7:3.4.11-0ubuntu0.1) ...\n",
"Cloning into 'decord'...\n",
"remote: Enumerating objects: 3211, done.\u001b[K\n",
"remote: Counting objects: 100% (300/300), done.\u001b[K\n",
"remote: Compressing objects: 100% (169/169), done.\u001b[K\n",
"remote: Total 3211 (delta 130), reused 256 (delta 103), pack-reused 2911\u001b[K\n",
"Receiving objects: 100% (3211/3211), 20.70 MiB | 29.89 MiB/s, done.\n",
"Resolving deltas: 100% (1941/1941), done.\n",
"Submodule '3rdparty/dlpack' (https://github.com/dmlc/dlpack) registered for path '3rdparty/dlpack'\n",
"Submodule '3rdparty/dmlc-core' (https://github.com/dmlc/dmlc-core) registered for path '3rdparty/dmlc-core'\n",
"Cloning into '/content/decord/3rdparty/dlpack'...\n",
"remote: Enumerating objects: 437, done. \n",
"remote: Counting objects: 100% (106/106), done. \n",
"remote: Compressing objects: 100% (43/43), done. \n",
"remote: Total 437 (delta 78), reused 68 (delta 61), pack-reused 331 \n",
"Receiving objects: 100% (437/437), 1.69 MiB | 7.53 MiB/s, done.\n",
"Resolving deltas: 100% (148/148), done.\n",
"Cloning into '/content/decord/3rdparty/dmlc-core'...\n",
"remote: Enumerating objects: 6284, done. \n",
"remote: Counting objects: 100% (148/148), done. \n",
"remote: Compressing objects: 100% (108/108), done. \n",
"remote: Total 6284 (delta 54), reused 74 (delta 24), pack-reused 6136 \n",
"Receiving objects: 100% (6284/6284), 1.68 MiB | 10.37 MiB/s, done.\n",
"Resolving deltas: 100% (3800/3800), done.\n",
"Submodule path '3rdparty/dlpack': checked out '5c792cef3aee54ad8b7000111c9dc1797f327b59'\n",
"Submodule path '3rdparty/dmlc-core': checked out 'd07fb7a443b5db8a89d65a15a024af6a425615a5'\n",
"/content/decord\n",
"/content/decord/build\n",
"-- The C compiler identification is GNU 7.5.0\n",
"-- The CXX compiler identification is GNU 7.5.0\n",
"-- Detecting C compiler ABI info\n",
"-- Detecting C compiler ABI info - done\n",
"-- Check for working C compiler: /usr/bin/cc - skipped\n",
"-- Detecting C compile features\n",
"-- Detecting C compile features - done\n",
"-- Detecting CXX compiler ABI info\n",
"-- Detecting CXX compiler ABI info - done\n",
"-- Check for working CXX compiler: /usr/bin/c++ - skipped\n",
"-- Detecting CXX compile features\n",
"-- Detecting CXX compile features - done\n",
"-- Found PkgConfig: /usr/bin/pkg-config (found version \"0.29.1\") \n",
"-- Checking for module 'libavcodec'\n",
"-- Found libavcodec, version 57.107.100\n",
"-- Checking for module 'libavformat'\n",
"-- Found libavformat, version 57.83.100\n",
"-- Checking for module 'libavutil'\n",
"-- Found libavutil, version 55.78.100\n",
"-- Checking for module 'libavdevice'\n",
"-- No package 'libavdevice' found\n",
"-- Checking for module 'libavfilter'\n",
"-- Found libavfilter, version 6.107.100\n",
"-- Checking for module 'libswresample'\n",
"-- Found libswresample, version 2.9.100\n",
"-- Unable to find libavdevice, device input API will not work!\n",
"-- Found FFMPEG or Libav: /usr/lib/x86_64-linux-gnu/libavformat.so;/usr/lib/x86_64-linux-gnu/libavfilter.so;/usr/lib/x86_64-linux-gnu/libavcodec.so;/usr/lib/x86_64-linux-gnu/libavutil.so;/usr/lib/x86_64-linux-gnu/libswresample.so, /usr/include/x86_64-linux-gnu\n",
"-- The CUDA compiler identification is NVIDIA 11.1.105\n",
"-- Detecting CUDA compiler ABI info\n",
"-- Detecting CUDA compiler ABI info - done\n",
"-- Check for working CUDA compiler: /usr/local/cuda/bin/nvcc - skipped\n",
"-- Detecting CUDA compile features\n",
"-- Detecting CUDA compile features - done\n",
"-- Performing Test SUPPORT_CXX11\n",
"-- Performing Test SUPPORT_CXX11 - Success\n",
"\u001b[0mFFMPEG_INCLUDE_DIR = /usr/include/x86_64-linux-gnu \u001b[0m\n",
"\u001b[0mFFMPEG_LIBRARIES = /usr/lib/x86_64-linux-gnu/libavformat.so;/usr/lib/x86_64-linux-gnu/libavfilter.so;/usr/lib/x86_64-linux-gnu/libavcodec.so;/usr/lib/x86_64-linux-gnu/libavutil.so;/usr/lib/x86_64-linux-gnu/libswresample.so \u001b[0m\n",
"-- Looking for pthread.h\n",
"-- Looking for pthread.h - found\n",
"-- Performing Test CMAKE_HAVE_LIBC_PTHREAD\n",
"-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed\n",
"-- Looking for pthread_create in pthreads\n",
"-- Looking for pthread_create in pthreads - not found\n",
"-- Looking for pthread_create in pthread\n",
"-- Looking for pthread_create in pthread - found\n",
"-- Found Threads: TRUE \n",
"-- Found CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda\n",
"-- Found CUDA_CUDA_LIBRARY=/usr/local/cuda/targets/x86_64-linux/lib/stubs/libcuda.so\n",
"-- Found CUDA_CUDART_LIBRARY=/usr/local/cuda/lib64/libcudart.so\n",
"-- Found CUDA_NVRTC_LIBRARY=/usr/local/cuda/lib64/libnvrtc.so\n",
"-- Found CUDA_CUDNN_LIBRARY=/usr/lib/x86_64-linux-gnu/libcudnn.so\n",
"-- Found CUDA_CUBLAS_LIBRARY=/usr/lib/x86_64-linux-gnu/libcublas.so\n",
"-- Found CUDA_NVIDIA_ML_LIBRARY=/usr/local/cuda/targets/x86_64-linux/lib/stubs/libnvidia-ml.so\n",
"-- Found CUDA_NVCUVID_LIBRARY=/usr/lib/x86_64-linux-gnu/libnvcuvid.so\n",
"-- Build with CUDA support\n",
"-- Configuring done\n",
"\u001b[33mCMake Warning (dev) in CMakeLists.txt:\n",
" Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,\n",
" empty CUDA_ARCHITECTURES not allowed. Run \"cmake --help-policy CMP0104\"\n",
" for policy details. Use the cmake_policy command to set the policy and\n",
" suppress this warning.\n",
"\n",
" CUDA_ARCHITECTURES is empty for target \"decord\".\n",
"This warning is for project developers. Use -Wno-dev to suppress it.\n",
"\u001b[0m\n",
"-- Generating done\n",
"-- Build files have been written to: /content/decord/build\n",
"[ 2%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/audio/audio_interface.cc.o\u001b[0m\n",
"[ 5%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/audio/audio_reader.cc.o\u001b[0m\n",
"[ 8%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/c_runtime_api.cc.o\u001b[0m\n",
"[ 10%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/cpu_device_api.cc.o\u001b[0m\n",
"[ 13%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/dso_module.cc.o\u001b[0m\n",
"[ 16%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/file_util.cc.o\u001b[0m\n",
"[ 18%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/module.cc.o\u001b[0m\n",
"[ 21%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/module_util.cc.o\u001b[0m\n",
"[ 24%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/ndarray.cc.o\u001b[0m\n",
"[ 27%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/registry.cc.o\u001b[0m\n",
"[ 29%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/str_util.cc.o\u001b[0m\n",
"[ 32%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/system_lib_module.cc.o\u001b[0m\n",
"[ 35%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/thread_pool.cc.o\u001b[0m\n",
"[ 37%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/threading_backend.cc.o\u001b[0m\n",
"[ 40%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/workspace_pool.cc.o\u001b[0m\n",
"[ 43%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/sampler/random_file_order_sampler.cc.o\u001b[0m\n",
"[ 45%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/sampler/random_sampler.cc.o\u001b[0m\n",
"[ 48%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/sampler/sequential_sampler.cc.o\u001b[0m\n",
"[ 51%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/sampler/smart_random_sampler.cc.o\u001b[0m\n",
"[ 54%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/logging.cc.o\u001b[0m\n",
"[ 56%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/storage_pool.cc.o\u001b[0m\n",
"[ 59%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/video_interface.cc.o\u001b[0m\n",
"[ 62%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/video_loader.cc.o\u001b[0m\n",
"[ 64%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/video_reader.cc.o\u001b[0m\n",
"[ 67%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/ffmpeg/filter_graph.cc.o\u001b[0m\n",
"[ 70%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/ffmpeg/threaded_decoder.cc.o\u001b[0m\n",
"[ 72%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/nvcodec/cuda_context.cc.o\u001b[0m\n",
"[ 75%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/nvcodec/cuda_decoder_impl.cc.o\u001b[0m\n",
"[ 78%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/nvcodec/cuda_mapped_frame.cc.o\u001b[0m\n",
"[ 81%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/nvcodec/cuda_parser.cc.o\u001b[0m\n",
"[ 83%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/nvcodec/cuda_stream.cc.o\u001b[0m\n",
"[ 86%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/nvcodec/cuda_texture.cc.o\u001b[0m\n",
"[ 89%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/video/nvcodec/cuda_threaded_decoder.cc.o\u001b[0m\n",
"[ 91%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/cuda/cuda_device_api.cc.o\u001b[0m\n",
"[ 94%] \u001b[32mBuilding CXX object CMakeFiles/decord.dir/src/runtime/cuda/cuda_module.cc.o\u001b[0m\n",
"[ 97%] \u001b[32mBuilding CUDA object CMakeFiles/decord.dir/src/improc/improc.cu.o\u001b[0m\n",
"[100%] \u001b[32m\u001b[1mLinking CXX shared library libdecord.so\u001b[0m\n",
"[100%] Built target decord\n",
"/content/decord/python\n",
"running install\n",
"running bdist_egg\n",
"running egg_info\n",
"creating decord.egg-info\n",
"writing decord.egg-info/PKG-INFO\n",
"writing dependency_links to decord.egg-info/dependency_links.txt\n",
"writing requirements to decord.egg-info/requires.txt\n",
"writing top-level names to decord.egg-info/top_level.txt\n",
"writing manifest file 'decord.egg-info/SOURCES.txt'\n",
"writing manifest file 'decord.egg-info/SOURCES.txt'\n",
"installing library code to build/bdist.linux-x86_64/egg\n",
"running install_lib\n",
"running build_py\n",
"creating build\n",
"creating build/lib\n",
"creating build/lib/decord\n",
"copying decord/__init__.py -> build/lib/decord\n",
"copying decord/audio_reader.py -> build/lib/decord\n",
"copying decord/av_reader.py -> build/lib/decord\n",
"copying decord/ndarray.py -> build/lib/decord\n",
"copying decord/video_reader.py -> build/lib/decord\n",
"copying decord/base.py -> build/lib/decord\n",
"copying decord/logging.py -> build/lib/decord\n",
"copying decord/video_loader.py -> build/lib/decord\n",
"copying decord/_api_internal.py -> build/lib/decord\n",
"creating build/lib/decord/function\n",
"copying decord/function/__init__.py -> build/lib/decord/function\n",
"copying decord/function/base.py -> build/lib/decord/function\n",
"creating build/lib/decord/data\n",
"copying decord/data/__init__.py -> build/lib/decord/data\n",
"copying decord/data/dataloader.py -> build/lib/decord/data\n",
"copying decord/data/base_action.py -> build/lib/decord/data\n",
"creating build/lib/decord/bridge\n",
"copying decord/bridge/__init__.py -> build/lib/decord/bridge\n",
"copying decord/bridge/torchdl.py -> build/lib/decord/bridge\n",
"copying decord/bridge/tvm.py -> build/lib/decord/bridge\n",
"copying decord/bridge/utils.py -> build/lib/decord/bridge\n",
"copying decord/bridge/mxnet.py -> build/lib/decord/bridge\n",
"copying decord/bridge/tf.py -> build/lib/decord/bridge\n",
"creating build/lib/decord/_ffi\n",
"copying decord/_ffi/function.py -> build/lib/decord/_ffi\n",
"copying decord/_ffi/runtime_ctypes.py -> build/lib/decord/_ffi\n",
"copying decord/_ffi/__init__.py -> build/lib/decord/_ffi\n",
"copying decord/_ffi/ndarray.py -> build/lib/decord/_ffi\n",
"copying decord/_ffi/libinfo.py -> build/lib/decord/_ffi\n",
"copying decord/_ffi/base.py -> build/lib/decord/_ffi\n",
"creating build/lib/decord/data/kinetics\n",
"copying decord/data/kinetics/__init__.py -> build/lib/decord/data/kinetics\n",
"copying decord/data/kinetics/kinetics400_action.py -> build/lib/decord/data/kinetics\n",
"creating build/lib/decord/data/transforms\n",
"copying decord/data/transforms/__init__.py -> build/lib/decord/data/transforms\n",
"copying decord/data/transforms/action.py -> build/lib/decord/data/transforms\n",
"creating build/lib/decord/_ffi/_cy2\n",
"copying decord/_ffi/_cy2/__init__.py -> build/lib/decord/_ffi/_cy2\n",
"creating build/lib/decord/_ffi/_ctypes\n",
"copying decord/_ffi/_ctypes/function.py -> build/lib/decord/_ffi/_ctypes\n",
"copying decord/_ffi/_ctypes/__init__.py -> build/lib/decord/_ffi/_ctypes\n",
"copying decord/_ffi/_ctypes/ndarray.py -> build/lib/decord/_ffi/_ctypes\n",
"copying decord/_ffi/_ctypes/types.py -> build/lib/decord/_ffi/_ctypes\n",
"creating build/lib/decord/_ffi/_cy3\n",
"copying decord/_ffi/_cy3/__init__.py -> build/lib/decord/_ffi/_cy3\n",
"copying decord/_ffi/README.md -> build/lib/decord/_ffi\n",
"creating build/lib/decord/_ffi/_cython\n",
"copying decord/_ffi/_cython/.gitignore -> build/lib/decord/_ffi/_cython\n",
"copying decord/_ffi/_cython/base.pxi -> build/lib/decord/_ffi/_cython\n",
"copying decord/_ffi/_cython/core.pyx -> build/lib/decord/_ffi/_cython\n",
"copying decord/_ffi/_cython/function.pxi -> build/lib/decord/_ffi/_cython\n",
"copying decord/_ffi/_cython/ndarray.pxi -> build/lib/decord/_ffi/_cython\n",
"copying decord/_ffi/_cython/node.pxi -> build/lib/decord/_ffi/_cython\n",
"running build_ext\n",
"creating build/bdist.linux-x86_64\n",
"creating build/bdist.linux-x86_64/egg\n",
"creating build/bdist.linux-x86_64/egg/decord\n",
"copying build/lib/decord/__init__.py -> build/bdist.linux-x86_64/egg/decord\n",
"creating build/bdist.linux-x86_64/egg/decord/function\n",
"copying build/lib/decord/function/__init__.py -> build/bdist.linux-x86_64/egg/decord/function\n",
"copying build/lib/decord/function/base.py -> build/bdist.linux-x86_64/egg/decord/function\n",
"copying build/lib/decord/audio_reader.py -> build/bdist.linux-x86_64/egg/decord\n",
"copying build/lib/decord/av_reader.py -> build/bdist.linux-x86_64/egg/decord\n",
"copying build/lib/decord/ndarray.py -> build/bdist.linux-x86_64/egg/decord\n",
"copying build/lib/decord/video_reader.py -> build/bdist.linux-x86_64/egg/decord\n",
"creating build/bdist.linux-x86_64/egg/decord/data\n",
"copying build/lib/decord/data/__init__.py -> build/bdist.linux-x86_64/egg/decord/data\n",
"copying build/lib/decord/data/dataloader.py -> build/bdist.linux-x86_64/egg/decord/data\n",
"copying build/lib/decord/data/base_action.py -> build/bdist.linux-x86_64/egg/decord/data\n",
"creating build/bdist.linux-x86_64/egg/decord/data/kinetics\n",
"copying build/lib/decord/data/kinetics/__init__.py -> build/bdist.linux-x86_64/egg/decord/data/kinetics\n",
"copying build/lib/decord/data/kinetics/kinetics400_action.py -> build/bdist.linux-x86_64/egg/decord/data/kinetics\n",
"creating build/bdist.linux-x86_64/egg/decord/data/transforms\n",
"copying build/lib/decord/data/transforms/__init__.py -> build/bdist.linux-x86_64/egg/decord/data/transforms\n",
"copying build/lib/decord/data/transforms/action.py -> build/bdist.linux-x86_64/egg/decord/data/transforms\n",
"creating build/bdist.linux-x86_64/egg/decord/bridge\n",
"copying build/lib/decord/bridge/__init__.py -> build/bdist.linux-x86_64/egg/decord/bridge\n",
"copying build/lib/decord/bridge/torchdl.py -> build/bdist.linux-x86_64/egg/decord/bridge\n",
"copying build/lib/decord/bridge/tvm.py -> build/bdist.linux-x86_64/egg/decord/bridge\n",
"copying build/lib/decord/bridge/utils.py -> build/bdist.linux-x86_64/egg/decord/bridge\n",
"copying build/lib/decord/bridge/mxnet.py -> build/bdist.linux-x86_64/egg/decord/bridge\n",
"copying build/lib/decord/bridge/tf.py -> build/bdist.linux-x86_64/egg/decord/bridge\n",
"copying build/lib/decord/base.py -> build/bdist.linux-x86_64/egg/decord\n",
"copying build/lib/decord/logging.py -> build/bdist.linux-x86_64/egg/decord\n",
"creating build/bdist.linux-x86_64/egg/decord/_ffi\n",
"copying build/lib/decord/_ffi/function.py -> build/bdist.linux-x86_64/egg/decord/_ffi\n",
"copying build/lib/decord/_ffi/runtime_ctypes.py -> build/bdist.linux-x86_64/egg/decord/_ffi\n",
"copying build/lib/decord/_ffi/__init__.py -> build/bdist.linux-x86_64/egg/decord/_ffi\n",
"copying build/lib/decord/_ffi/ndarray.py -> build/bdist.linux-x86_64/egg/decord/_ffi\n",
"copying build/lib/decord/_ffi/libinfo.py -> build/bdist.linux-x86_64/egg/decord/_ffi\n",
"creating build/bdist.linux-x86_64/egg/decord/_ffi/_cy2\n",
"copying build/lib/decord/_ffi/_cy2/__init__.py -> build/bdist.linux-x86_64/egg/decord/_ffi/_cy2\n",
"creating build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes\n",
"copying build/lib/decord/_ffi/_ctypes/function.py -> build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes\n",
"copying build/lib/decord/_ffi/_ctypes/__init__.py -> build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes\n",
"copying build/lib/decord/_ffi/_ctypes/ndarray.py -> build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes\n",
"copying build/lib/decord/_ffi/_ctypes/types.py -> build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes\n",
"copying build/lib/decord/_ffi/base.py -> build/bdist.linux-x86_64/egg/decord/_ffi\n",
"creating build/bdist.linux-x86_64/egg/decord/_ffi/_cython\n",
"copying build/lib/decord/_ffi/_cython/base.pxi -> build/bdist.linux-x86_64/egg/decord/_ffi/_cython\n",
"copying build/lib/decord/_ffi/_cython/node.pxi -> build/bdist.linux-x86_64/egg/decord/_ffi/_cython\n",
"copying build/lib/decord/_ffi/_cython/ndarray.pxi -> build/bdist.linux-x86_64/egg/decord/_ffi/_cython\n",
"copying build/lib/decord/_ffi/_cython/function.pxi -> build/bdist.linux-x86_64/egg/decord/_ffi/_cython\n",
"copying build/lib/decord/_ffi/_cython/core.pyx -> build/bdist.linux-x86_64/egg/decord/_ffi/_cython\n",
"copying build/lib/decord/_ffi/_cython/.gitignore -> build/bdist.linux-x86_64/egg/decord/_ffi/_cython\n",
"copying build/lib/decord/_ffi/README.md -> build/bdist.linux-x86_64/egg/decord/_ffi\n",
"creating build/bdist.linux-x86_64/egg/decord/_ffi/_cy3\n",
"copying build/lib/decord/_ffi/_cy3/__init__.py -> build/bdist.linux-x86_64/egg/decord/_ffi/_cy3\n",
"copying build/lib/decord/video_loader.py -> build/bdist.linux-x86_64/egg/decord\n",
"copying build/lib/decord/_api_internal.py -> build/bdist.linux-x86_64/egg/decord\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/function/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/function/base.py to base.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/audio_reader.py to audio_reader.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/av_reader.py to av_reader.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/ndarray.py to ndarray.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/video_reader.py to video_reader.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/data/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/data/dataloader.py to dataloader.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/data/base_action.py to base_action.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/data/kinetics/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/data/kinetics/kinetics400_action.py to kinetics400_action.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/data/transforms/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/data/transforms/action.py to action.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/bridge/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/bridge/torchdl.py to torchdl.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/bridge/tvm.py to tvm.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/bridge/utils.py to utils.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/bridge/mxnet.py to mxnet.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/bridge/tf.py to tf.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/base.py to base.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/logging.py to logging.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/function.py to function.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/runtime_ctypes.py to runtime_ctypes.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/ndarray.py to ndarray.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/libinfo.py to libinfo.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/_cy2/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes/function.py to function.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes/ndarray.py to ndarray.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/_ctypes/types.py to types.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/base.py to base.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_ffi/_cy3/__init__.py to __init__.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/video_loader.py to video_loader.cpython-37.pyc\n",
"byte-compiling build/bdist.linux-x86_64/egg/decord/_api_internal.py to _api_internal.cpython-37.pyc\n",
"installing package data to build/bdist.linux-x86_64/egg\n",
"running install_data\n",
"copying ../build/libdecord.so -> build/bdist.linux-x86_64/egg/decord\n",
"creating build/bdist.linux-x86_64/egg/EGG-INFO\n",
"copying decord.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO\n",
"copying decord.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n",
"copying decord.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n",
"copying decord.egg-info/not-zip-safe -> build/bdist.linux-x86_64/egg/EGG-INFO\n",
"copying decord.egg-info/requires.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n",
"copying decord.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n",
"creating dist\n",
"creating 'dist/decord-0.6.0-py3.7-linux-x86_64.egg' and adding 'build/bdist.linux-x86_64/egg' to it\n",
"removing 'build/bdist.linux-x86_64/egg' (and everything under it)\n",
"Processing decord-0.6.0-py3.7-linux-x86_64.egg\n",
"creating /root/.local/lib/python3.7/site-packages/decord-0.6.0-py3.7-linux-x86_64.egg\n",
"Extracting decord-0.6.0-py3.7-linux-x86_64.egg to /root/.local/lib/python3.7/site-packages\n",
"Adding decord 0.6.0 to easy-install.pth file\n",
"\n",
"Installed /root/.local/lib/python3.7/site-packages/decord-0.6.0-py3.7-linux-x86_64.egg\n",
"Processing dependencies for decord==0.6.0\n",
"Searching for numpy==1.21.6\n",
"Best match: numpy 1.21.6\n",
"Adding numpy 1.21.6 to easy-install.pth file\n",
"Installing f2py script to /root/.local/bin\n",
"Installing f2py3 script to /root/.local/bin\n",
"Installing f2py3.7 script to /root/.local/bin\n",
"\n",
"Using /usr/local/lib/python3.7/dist-packages\n",
"Finished processing dependencies for decord==0.6.0\n",
"/content\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"获取一些样例视频"
],
"metadata": {
"id": "g0NcyvNuW7gs"
}
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"id": "BPo1CIVsG3DB"
},
"outputs": [],
"source": [
"# 提前在Drive里准备好的一个视频 50M 30min\n",
"!cp ./drive/MyDrive/sample_videos/long.mp4 ."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2s8pQRYZIr93",
"outputId": "2d346604-7674-4180-eed5-08d038da976e"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"[youtube] jNQXAC9IVRw: Downloading webpage\n",
"[download] Destination: short.f133.mp4\n",
"\u001b[K[download] 100% of 200.32KiB in 00:03\n",
"[download] Destination: short.mp4.f140\n",
"\u001b[K[download] 100% of 301.95KiB in 00:04\n",
"[ffmpeg] Merging formats into \"short.mp4\"\n",
"Deleting original file short.f133.mp4 (pass -k to keep)\n",
"Deleting original file short.mp4.f140 (pass -k to keep)\n"
]
}
],
"source": [
"# 从youtube上下载一个短视频\n",
"!youtube-dl 'https://www.youtube.com/watch?v=jNQXAC9IVRw' -o short.mp4 -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'"
]
},
{
"cell_type": "code",
"source": [
"# 从filesamples上下载一个4K视频 126M\n",
"!curl -O https://filesamples.com/samples/video/mp4/sample_3840x2160.mp4 # 126M 4k vid\n",
"!mv sample_3840x2160.mp4 big.mp4"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "b4qxV7iTq1ZK",
"outputId": "c7e2b6b3-3439-4fe6-a55f-cd07abb84d5b"
},
"execution_count": 6,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
" % Total % Received % Xferd Average Speed Time Time Time Current\n",
" Dload Upload Total Spent Left Speed\n",
"100 126M 0 126M 0 0 89.0M 0 --:--:-- 0:00:01 --:--:-- 89.0M\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"## 内存使用分析\n",
"\n",
"+ `decord`的内存占用一般,不会把所有数据都载入,GPU版本和CPU版本在视频长度不同的情况下内存占用表现不一样。总体来说可以接受。\n",
"+ `mmcv`一导入就占据了很多内存(这个库重点不在读取视频,所以会加载很多其他的),初始化的时候不会占用很多内存,但是每读取一帧就增加一点内存?\n",
"+ `pyAV`和`OpenCV`差不多,内存使用不多"
],
"metadata": {
"id": "Tu3zzFXDW-gI"
}
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "pKcgK6D4Kys_",
"outputId": "0ce271a0-9f98-4931-8f45-9b9a6544d80d"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Filename: tmp.py\n",
"\n",
"Line # Mem usage Increment Occurrences Line Contents\n",
"=============================================================\n",
" 4 76.219 MiB 76.219 MiB 1 @profile\n",
" 5 def my_func():\n",
" 6 107.246 MiB 31.027 MiB 1 vr = VideoReader('big.mp4', ctx=cpu(0))\n",
" 7 369.172 MiB 261.926 MiB 1 img = vr[0]\n",
" 8 421.359 MiB 52.188 MiB 1 img = vr[1]\n",
" 9 421.359 MiB 0.000 MiB 1 img = vr[2]\n",
" 10 425.477 MiB 4.117 MiB 1 img = vr[3]\n",
" 11 425.477 MiB 0.000 MiB 1 img = vr[4]\n",
" 12 437.328 MiB 11.852 MiB 1 img = vr[5]\n",
" 13 437.328 MiB 0.000 MiB 1 img = vr[6]\n",
" 14 438.352 MiB 1.023 MiB 1 img = vr[7]\n",
" 15 438.352 MiB 0.000 MiB 1 img = vr[8]\n",
" 16 438.352 MiB 0.000 MiB 1 img = vr[9]\n",
"\n",
"\n",
"CPU times: user 13.2 ms, sys: 30.3 ms, total: 43.5 ms\n",
"Wall time: 1.66 s\n"
]
}
],
"source": [
"code = \"\"\"\n",
"from decord import VideoReader\n",
"from decord import cpu\n",
"@profile\n",
"def my_func():\n",
" vr = VideoReader('big.mp4', ctx=cpu(0))\n",
" img = vr[0]\n",
" img = vr[1]\n",
" img = vr[2]\n",
" img = vr[3]\n",
" img = vr[4]\n",
" img = vr[5]\n",
" img = vr[6]\n",
" img = vr[7]\n",
" img = vr[8]\n",
" img = vr[9]\n",
"\n",
"if __name__ == '__main__':\n",
" my_func()\n",
"\"\"\"\n",
"with open(\"tmp.py\", \"w+\") as f:\n",
" f.write(code)\n",
"%time !python -m memory_profiler tmp.py"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "9983ce8c-fdee-4313-8024-56fbfa7661ba",
"id": "SfxIAFYYu_Un"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Filename: tmp.py\n",
"\n",
"Line # Mem usage Increment Occurrences Line Contents\n",
"=============================================================\n",
" 4 76.250 MiB 76.250 MiB 1 @profile\n",
" 5 def my_func():\n",
" 6 198.934 MiB 122.684 MiB 1 vr = VideoReader('big.mp4', ctx=gpu(0))\n",
" 7 263.465 MiB 64.531 MiB 1 img = vr[0]\n",
" 8 263.465 MiB 0.000 MiB 1 img = vr[1]\n",
" 9 263.465 MiB 0.000 MiB 1 img = vr[2]\n",
" 10 263.465 MiB 0.000 MiB 1 img = vr[3]\n",
" 11 263.465 MiB 0.000 MiB 1 img = vr[4]\n",
" 12 263.465 MiB 0.000 MiB 1 img = vr[5]\n",
" 13 263.465 MiB 0.000 MiB 1 img = vr[6]\n",
" 14 263.465 MiB 0.000 MiB 1 img = vr[7]\n",
" 15 263.465 MiB 0.000 MiB 1 img = vr[8]\n",
" 16 263.465 MiB 0.000 MiB 1 img = vr[9]\n",
"\n",
"\n",
"CPU times: user 14.2 ms, sys: 34.4 ms, total: 48.6 ms\n",
"Wall time: 1.16 s\n"
]
}
],
"source": [
"code = \"\"\"\n",
"from decord import VideoReader\n",
"from decord import gpu\n",
"@profile\n",
"def my_func():\n",
" vr = VideoReader('big.mp4', ctx=gpu(0))\n",
" img = vr[0]\n",
" img = vr[1]\n",
" img = vr[2]\n",
" img = vr[3]\n",
" img = vr[4]\n",
" img = vr[5]\n",
" img = vr[6]\n",
" img = vr[7]\n",
" img = vr[8]\n",
" img = vr[9]\n",
"\n",
"if __name__ == '__main__':\n",
" my_func()\n",
"\"\"\"\n",
"with open(\"tmp.py\", \"w+\") as f:\n",
" f.write(code)\n",
"%time !python -m memory_profiler tmp.py"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "KuNbH-OMVHOY",
"outputId": "7c1c8043-f6c2-41f0-cf78-711c1890e544"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Filename: tmp.py\n",
"\n",
"Line # Mem usage Increment Occurrences Line Contents\n",
"=============================================================\n",
" 3 281.496 MiB 281.496 MiB 1 @profile\n",
" 4 def my_func():\n",
" 5 308.559 MiB 27.062 MiB 1 v = VideoReader('big.mp4')\n",
" 6 411.469 MiB 102.910 MiB 1 img = next(v)\n",
" 7 451.512 MiB 40.043 MiB 1 img = next(v)\n",
" 8 479.375 MiB 27.863 MiB 1 img = next(v)\n",
" 9 503.137 MiB 23.762 MiB 1 img = next(v)\n",
" 10 526.883 MiB 23.746 MiB 1 img = next(v)\n",
" 11 562.488 MiB 35.605 MiB 1 img = next(v)\n",
" 12 586.500 MiB 24.012 MiB 1 img = next(v)\n",
" 13 610.258 MiB 23.758 MiB 1 img = next(v)\n",
" 14 638.711 MiB 28.453 MiB 1 img = next(v)\n",
" 15 662.793 MiB 24.082 MiB 1 img = next(v)\n",
"\n",
"\n",
"CPU times: user 27 ms, sys: 25.4 ms, total: 52.4 ms\n",
"Wall time: 2.86 s\n"
]
}
],
"source": [
"code = \"\"\"\n",
"from mmcv import VideoReader\n",
"@profile\n",
"def my_func():\n",
" v = VideoReader('big.mp4')\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
" img = next(v)\n",
"\n",
"if __name__ == '__main__':\n",
" my_func()\n",
"\"\"\"\n",
"with open(\"tmp.py\", \"w+\") as f:\n",
" f.write(code)\n",
"%time !python -m memory_profiler tmp.py"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xwAh-RAHV57N",
"outputId": "17dd0271-78ad-4f01-e05f-f3b4b1587ff7"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Filename: tmp.py\n",
"\n",
"Line # Mem usage Increment Occurrences Line Contents\n",
"=============================================================\n",
" 3 76.363 MiB 76.363 MiB 1 @profile\n",
" 4 def my_func():\n",
" 5 104.723 MiB 28.359 MiB 1 cap = cv2.VideoCapture(\"big.mp4\")\n",
" 6 208.176 MiB 103.453 MiB 1 frame_exists, rgb = cap.read()\n",
" 7 247.961 MiB 39.785 MiB 1 frame_exists, rgb = cap.read()\n",
" 8 271.719 MiB 23.758 MiB 1 frame_exists, rgb = cap.read()\n",
" 9 271.719 MiB 0.000 MiB 1 frame_exists, rgb = cap.read()\n",
" 10 271.719 MiB 0.000 MiB 1 frame_exists, rgb = cap.read()\n",
" 11 271.719 MiB 0.000 MiB 1 frame_exists, rgb = cap.read()\n",
" 12 271.719 MiB 0.000 MiB 1 frame_exists, rgb = cap.read()\n",
" 13 271.719 MiB 0.000 MiB 1 frame_exists, rgb = cap.read()\n",
" 14 271.719 MiB 0.000 MiB 1 frame_exists, rgb = cap.read()\n",
" 15 271.969 MiB 0.250 MiB 1 frame_exists, rgb = cap.read()\n",
"\n",
"\n",
"CPU times: user 12.1 ms, sys: 32.3 ms, total: 44.4 ms\n",
"Wall time: 1.46 s\n"
]
}
],
"source": [
"code = \"\"\"\n",
"import cv2\n",
"@profile\n",
"def my_func():\n",
" cap = cv2.VideoCapture(\"big.mp4\")\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
" frame_exists, rgb = cap.read()\n",
"\n",
"if __name__ == '__main__':\n",
" my_func()\n",
"\"\"\"\n",
"with open(\"tmp.py\", \"w+\") as f:\n",
" f.write(code)\n",
"%time !python -m memory_profiler tmp.py"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "ceaed6d9-1c17-4501-e295-7419f82db73f",
"id": "gejDzyu9r608"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Filename: tmp.py\n",
"\n",
"Line # Mem usage Increment Occurrences Line Contents\n",
"=============================================================\n",
" 4 55.141 MiB 55.141 MiB 1 @profile\n",
" 5 def my_func():\n",
" 6 81.105 MiB 25.965 MiB 1 with av.open(\"big.mp4\") as container:\n",
" 7 81.105 MiB 0.000 MiB 1 stream = container.streams.video[0]\n",
" 8 81.105 MiB 0.000 MiB 1 decoder = container.decode(stream)\n",
" 9 151.891 MiB 70.785 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 10 192.848 MiB 40.957 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 11 216.438 MiB 23.590 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 12 216.672 MiB 0.234 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 13 216.688 MiB 0.016 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 14 216.688 MiB 0.000 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 15 216.695 MiB 0.008 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 16 216.695 MiB 0.000 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 17 216.695 MiB 0.000 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" 18 216.703 MiB 0.008 MiB 1 array = next(decoder).to_ndarray(format=\"rgb24\")\n",
"\n",
"\n"
]
}
],
"source": [
"code = \"\"\"\n",
"import av\n",
"\n",
"@profile\n",
"def my_func():\n",
" with av.open(\"big.mp4\") as container:\n",
" stream = container.streams.video[0]\n",
" decoder = container.decode(stream)\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
" array = next(decoder).to_ndarray(format=\"rgb24\")\n",
"if __name__ == '__main__':\n",
" my_func()\n",
"\"\"\"\n",
"with open(\"tmp.py\", \"w+\") as f:\n",
" f.write(code)\n",
"!python -m memory_profiler tmp.py"
]
},
{
"cell_type": "markdown",
"source": [
"## 接口比较\n",
"\n",
"每个方法都实现顺序读取视频和随机读取视频。\n",
"\n",
"+ `decord`和`mmcv`提供的接口很方便,面向对象,基本没有什么门槛。\n",
"+ `OpenCV`提供的接口没有那么方便,和c更接近一些,获取一些属性要先翻文档,\n",
"+ `pyAV`太底层了,是ffmpeg的python包装,更擅长处理不同格式视频流,不是很方便。由于其seek方法是基于时间的,没有找到基于帧序号的……"
],
"metadata": {
"id": "-ZQsW1QP8aPl"
}
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"id": "O1D5SFpNu2eU"
},
"outputs": [],
"source": [
"import decord\n",
"import mmcv\n",
"import cv2\n",
"import time\n",
"import random\n",
"from tqdm import tqdm\n",
"from decord import cpu, gpu\n",
"import av\n",
"def seq_read_decord(path, use_tqdm=True):\n",
" vr = decord.VideoReader(path, ctx=cpu(0))\n",
" for i in tqdm(range(len(vr)), disable=not use_tqdm):\n",
" img = vr[i]\n",
"def random_read_decord(path, random_num=100, use_tqdm=True):\n",
" vr = decord.VideoReader(path, ctx=cpu(0))\n",
" vl = len(vr)\n",
" for _ in tqdm(range(random_num), disable=not use_tqdm):\n",
" i = random.randrange(0, vl)\n",
" frame = vr[i]\n",
"\n",
"def seq_read_decord_gpu(path, use_tqdm=True):\n",
" vr = decord.VideoReader(path, ctx=gpu(0))\n",
" for i in tqdm(range(len(vr)), disable=not use_tqdm):\n",
" img = vr[i]\n",
"def random_read_decord_gpu(path, random_num=100, use_tqdm=True):\n",
" vr = decord.VideoReader(path, ctx=gpu(0))\n",
" vl = len(vr)\n",
" for _ in tqdm(range(random_num), disable=not use_tqdm):\n",
" i = random.randrange(0, vl)\n",
" frame = vr[i]\n",
"\n",
"def seq_read_mmcv(path, use_tqdm=True):\n",
" vr = mmcv.VideoReader(path)\n",
" for img in tqdm(vr, disable=not use_tqdm):\n",
" frame = img\n",
"def random_read_mmcv(path, random_num=100, use_tqdm=True):\n",
" vr = mmcv.VideoReader(path)\n",
" vl = len(vr)\n",
" for _ in tqdm(range(random_num), disable=not use_tqdm):\n",
" i = random.randrange(0, vl)\n",
" frame = vr[i]\n",
"\n",
"def seq_read_cv2(path, use_tqdm=True):\n",
" cap = cv2.VideoCapture(path)\n",
" pbar = tqdm(total=cap.get(cv2.CAP_PROP_FRAME_COUNT), disable=not use_tqdm)\n",
" while cap.isOpened():\n",
" frame_exists, rgb = cap.read()\n",
" pbar.update(1)\n",
" if frame_exists:\n",
" rgb = cv2.cvtColor(rgb, cv2.COLOR_BGR2RGB) # we need rgb numpy\n",
" else:\n",
" cap.release()\n",
" pbar.close()\n",
" break\n",
"def random_read_cv2(path, random_num=100, use_tqdm=True):\n",
" cap = cv2.VideoCapture(path)\n",
" vl = cap.get(cv2.CAP_PROP_FRAME_COUNT)\n",
" for _ in tqdm(range(random_num), disable=not use_tqdm):\n",
" i = random.randrange(0, vl)\n",
" cap.set(cv2.CAP_PROP_POS_FRAMES, i)\n",
" frame_exists, rgb = cap.read()\n",
" if frame_exists:\n",
" rgb = cv2.cvtColor(rgb, cv2.COLOR_BGR2RGB)\n",
" else:\n",
" cap.release()\n",
" break\n",
"\n",
"def seq_read_av(path, use_tqdm=True):\n",
" with av.open(path) as container:\n",
" stream = container.streams.video[0]\n",
" for frame in tqdm(container.decode(stream), disable=not use_tqdm):\n",
" array = frame.to_ndarray(format=\"rgb24\")\n",
" # print(type(array), array.dtype, array.shape)\n",
"\n",
"def random_read_av(path, random_num=100, use_tqdm=True):\n",
" # 要获取特定的第n帧太难了……\n",
" pass\n"
]
},
{
"cell_type": "markdown",
"source": [
"## 进行速度测试\n",
"\n",
"`OpenCV`在各方面表现都不错,可以作为一个基准进行比较。\n",
"\n",
"`decord`的GPU版本可能是在读取视频的时候要用GPU初始化,比较耗时,所以处理短视频较慢,而在长视频和4K视频中比其他方法强很多。其CPU版本比`OpenCV`略差一些。\n",
"\n",
"`mmcv`和`OpenCV`基本一致,在长视频和4K视频的顺序读取略强,在4K视频的随机读取略弱。\n",
"\n",
"`pyAV`在测试中没有表现出特点,结果都是较慢。\n",
"\n",
"> 由于时间原因,可能比较不是特别全面,多次运行可能会得到不同的结果,但是比较明显的结论不会改变:GPU版本的decord在处理数据量更大的视频时优势很明显。\n",
"\n",
"![临时算IO榜单_00.png](data:image/png;base64,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HiOAkOFMGpfIqvcLCRoyjrEXXhniZO/WnZSb+zEtq3+Tz4+aozPJGvYG2/K2s/XobQxMrbdUV95/0iMYfr/fv3//flJSUrBa2/yItEj35a3h1PETlDoNQiLj6RUX1uQZCW9NCceKyvDYYumdHH3JszZ4qiguLKbCbSUyoTfx4U2sxVNHVZ1BSPilEx6c5yo/zrFTTuzxfUiMsILXSXUd2MOa/84lZa0t4+SpMmrcZkJjE0l0NHWe1k1NxRmsjrDWn8X11nLqeBGldWCP7kVSbGg3fidSPd2ujbioPHmS0hoftuhe9GrQPtrRLqCLtw0XNZVugiJCGx0Auqiu9BAcEdLocw+1lU5MoWHYzIFcR8PvNV9Hly5bXVEHdgdhXXUWfW8Np44XcbrGiyUslsTEGEIu2S8u9rz6H/zXhzbm//rnzE+q4XhBCc6QOPokOpqf/KWl+G0u5jy1VDpNhDYZVz2hftrSF3gpev//8e+vHGH4w7/l+9OiLv7FWUW1JxjH5X68p5aKGj8hjsbxA113/0l35XK5OHLkCNHR0UqwREREpCtrlGD10805nYbnMG/94ue8VTKWb/7220zpAheuRdqrfoKlSS5EREREJOBcB9aw/rCXyJHjGaXkSnoQneYRERGRLsxM7OCpzPZaGRipw5rOxOmNZfjsW0i9djSaRF16Et0iKCIiIiIicgV0i6CIiIiIiMjnQAmWiIiIiIhIgCjBEhERERERCRAlWCIiIiIiIgGiBEtERERERCRAlGCJiIiIiIgEiBIsERERERGRAFGCJSIiIiIiEiBKsERERERERAJECZaIiIiIiEiAKMESEREREREJECVYIiIiIiIiAaIES0REREREJECUYImIiIiIiASIEiwREREREZEAUYIlIiIiIiISIEqwREREREREAkQJloiIiIiISIAowRIREREREQkQJVgiIiIiIiIBYjn/j9OnT2OxWC63rIiIiIiIiDTidrsv/PtCRlVZWdkhhREREREREekOLBYL/x8Knd8yu/jirwAAAABJRU5ErkJggg==)"
],
"metadata": {
"id": "CfPLa5oE921n"
}
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"id": "-DdP0tMYwYdB"
},
"outputs": [],
"source": [
"def seq_read(func, path, repeat, use_tqdm=True):\n",
" start_time = time.time()\n",
" for _ in range(repeat):\n",
" func(path, use_tqdm=use_tqdm)\n",
" end_time = time.time()\n",
" return end_time - start_time\n",
"def random_read(func, path, repeat, random_num, use_tqdm=True):\n",
" start_time = time.time()\n",
" for _ in range(repeat):\n",
" func(path, random_num, use_tqdm=use_tqdm)\n",
" end_time = time.time()\n",
" return end_time - start_time"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rG1e_z5fz-dv",
"outputId": "1da3281d-2df3-4d27-d94b-d6614548ff8f"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"For short video: \n",
"Sequential Read[100x]:\n",
"Decord GPU: 19.576740026474\n",
"Decord: 14.319761991500854\n",
"MMCV: 11.701236248016357\n",
"OpenCV: 11.556411266326904\n",
"PyAV: 17.922401189804077\n",
"Random Read[1x]:\n"
]
}
],
"source": [
"seq_repeat = 100\n",
"path = \"short.mp4\"\n",
"print(f\"For short video: \")\n",
"print(f\"Sequential Read[{seq_repeat}x]:\")\n",
"print(f\"Decord GPU: {seq_read(seq_read_decord_gpu, path, seq_repeat, use_tqdm=False)}\")\n",
"print(f\"Decord: {seq_read(seq_read_decord, path, seq_repeat, use_tqdm=False)}\")\n",
"print(f\"MMCV: {seq_read(seq_read_mmcv, path, seq_repeat, use_tqdm=False)}\")\n",
"print(f\"OpenCV: {seq_read(seq_read_cv2, path, seq_repeat, use_tqdm=False)}\")\n",
"print(f\"PyAV: {seq_read(seq_read_av, path, seq_repeat, use_tqdm=False)}\")"
]
},
{
"cell_type": "code",
"source": [
"path = \"short.mp4\"\n",
"random_repeat = 1\n",
"random_num = 100\n",
"print(f\"Random Read[{random_repeat}x]:\")\n",
"print(f\"Decord GPU: {random_read(random_read_decord_gpu, path, random_repeat, random_num, use_tqdm=False)}\")\n",
"print(f\"Decord: {random_read(random_read_decord, path, random_repeat, random_num, use_tqdm=False)}\")\n",
"print(f\"MMCV: {random_read(random_read_mmcv, path, random_repeat, random_num, use_tqdm=False)}\")\n",
"print(f\"OpenCV: {random_read(random_read_cv2, path, random_repeat, random_num, use_tqdm=False)}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "97Y6UaXYe6pV",
"outputId": "bb893fa8-6b9f-4c69-8aec-a6992231e24a"
},
"execution_count": 7,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Random Read[1x]:\n",
"Decord GPU: 5.913957834243774\n",
"Decord: 1.5877439975738525\n",
"MMCV: 1.6674537658691406\n",
"OpenCV: 1.8470497131347656\n"
]
}
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JR5XFOCEz_sh",
"outputId": "4233be5d-50e3-49bc-df3d-4e35a64cb972"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"For long video: \n",
"Sequential Read[1x]:\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 45000/45000 [01:13<00:00, 614.93it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord GPU: 73.3991289138794\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 45000/45000 [04:22<00:00, 171.58it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord: 262.47067618370056\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|█████████▉| 44998/45000 [03:33<00:00, 210.65it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"MMCV: 213.643714427948\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|█████████▉| 44999/45000.0 [04:15<00:00, 175.97it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"OpenCV: 255.74768257141113\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"44998it [03:46, 198.68it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"PyAV: 226.53186297416687\n",
"Random Read[5x]:\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 100/100 [00:18<00:00, 5.52it/s]\n",
"100%|██████████| 100/100 [00:17<00:00, 5.59it/s]\n",
"100%|██████████| 100/100 [00:16<00:00, 6.02it/s]\n",
"100%|██████████| 100/100 [00:18<00:00, 5.40it/s]\n",
"100%|██████████| 100/100 [00:18<00:00, 5.32it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord GPU: 90.98765110969543\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 100/100 [00:41<00:00, 2.39it/s]\n",
"100%|██████████| 100/100 [00:41<00:00, 2.42it/s]\n",
"100%|██████████| 100/100 [00:41<00:00, 2.39it/s]\n",
"100%|██████████| 100/100 [00:44<00:00, 2.22it/s]\n",
"100%|██████████| 100/100 [00:41<00:00, 2.39it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord: 212.76363229751587\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 100/100 [00:34<00:00, 2.92it/s]\n",
"100%|██████████| 100/100 [00:34<00:00, 2.88it/s]\n",
"100%|██████████| 100/100 [00:37<00:00, 2.64it/s]\n",
"100%|██████████| 100/100 [00:36<00:00, 2.73it/s]\n",
"100%|██████████| 100/100 [00:34<00:00, 2.91it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"MMCV: 178.0106749534607\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 100/100 [00:34<00:00, 2.90it/s]\n",
"100%|██████████| 100/100 [00:33<00:00, 2.96it/s]\n",
"100%|██████████| 100/100 [00:33<00:00, 3.00it/s]\n",
"100%|██████████| 100/100 [00:35<00:00, 2.81it/s]\n",
"100%|██████████| 100/100 [00:37<00:00, 2.63it/s]"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"OpenCV: 175.26724076271057\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"\n"
]
}
],
"source": [
"seq_repeat = 1\n",
"random_repeat = 5\n",
"random_num = 100\n",
"path = \"long.mp4\"\n",
"print(f\"For long video: \")\n",
"print(f\"Sequential Read[{seq_repeat}x]:\")\n",
"print(f\"Decord GPU: {seq_read(seq_read_decord_gpu, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"Decord: {seq_read(seq_read_decord, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"MMCV: {seq_read(seq_read_mmcv, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"OpenCV: {seq_read(seq_read_cv2, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"PyAV: {seq_read(seq_read_av, path, seq_repeat, use_tqdm=True)}\")\n",
"\n",
"print(f\"Random Read[{random_repeat}x]:\")\n",
"print(f\"Decord GPU: {random_read(random_read_decord_gpu, path, random_repeat, random_num, use_tqdm=True)}\")\n",
"print(f\"Decord: {random_read(random_read_decord, path, random_repeat, random_num, use_tqdm=True)}\")\n",
"print(f\"MMCV: {random_read(random_read_mmcv, path, random_repeat, random_num, use_tqdm=True)}\")\n",
"print(f\"OpenCV: {random_read(random_read_cv2, path, random_repeat, random_num, use_tqdm=True)}\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 991
},
"outputId": "5cfbeae0-858a-4df6-bb52-81068752deff",
"id": "cDlitQxS_RDn"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"For big video: \n",
"Sequential Read[5x]:\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 677/677 [00:04<00:00, 155.42it/s]\n",
"100%|██████████| 677/677 [00:04<00:00, 162.28it/s]\n",
"100%|██████████| 677/677 [00:04<00:00, 165.06it/s]\n",
"100%|██████████| 677/677 [00:04<00:00, 160.76it/s]\n",
"100%|██████████| 677/677 [00:04<00:00, 161.86it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord GPU: 22.91811966896057\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 677/677 [00:41<00:00, 16.45it/s]\n",
"100%|██████████| 677/677 [00:37<00:00, 18.08it/s]\n",
"100%|██████████| 677/677 [00:37<00:00, 18.22it/s]\n",
"100%|██████████| 677/677 [00:38<00:00, 17.36it/s]\n",
"100%|██████████| 677/677 [00:36<00:00, 18.37it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord: 192.9010877609253\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 677/677 [00:35<00:00, 19.27it/s]\n",
"100%|██████████| 677/677 [00:34<00:00, 19.46it/s]\n",
"100%|██████████| 677/677 [00:36<00:00, 18.55it/s]\n",
"100%|██████████| 677/677 [00:34<00:00, 19.42it/s]\n",
"100%|██████████| 677/677 [00:34<00:00, 19.45it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"MMCV: 176.829448223114\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"678it [00:38, 17.81it/s] \n",
"678it [00:39, 17.19it/s] \n",
"678it [00:37, 17.86it/s] \n",
"678it [00:37, 17.85it/s] \n",
"678it [00:39, 17.11it/s] \n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"OpenCV: 193.79467034339905\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"677it [00:39, 17.21it/s]\n",
"677it [00:39, 17.23it/s]\n",
"677it [00:41, 16.46it/s]\n",
"677it [00:39, 17.01it/s]\n",
"677it [00:40, 16.89it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"PyAV: 200.42598056793213\n",
"Random Read[5x]:\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
" 28%|██▊ | 28/100 [00:19<00:48, 1.47it/s]\n"
]
},
{
"output_type": "error",
"ename": "DECORDError",
"evalue": "ignored",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mDECORDError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-8-54aa6a942424>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Random Read[{random_repeat}x]:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Decord GPU: {random_read(random_read_decord_gpu, path, random_repeat, random_num, use_tqdm=True)}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 15\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Decord: {random_read(random_read_decord, path, random_repeat, random_num, use_tqdm=True)}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"MMCV: {random_read(random_read_mmcv, path, random_repeat, random_num, use_tqdm=True)}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-2-976d9979c9a7>\u001b[0m in \u001b[0;36mrandom_read\u001b[0;34m(func, path, repeat, random_num, use_tqdm)\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0mstart_time\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrepeat\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrandom_num\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0muse_tqdm\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0muse_tqdm\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 11\u001b[0m \u001b[0mend_time\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mend_time\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mstart_time\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-1-f86f577dfcde>\u001b[0m in \u001b[0;36mrandom_read_decord_gpu\u001b[0;34m(path, random_num, use_tqdm)\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtqdm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrandom_num\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdisable\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mnot\u001b[0m \u001b[0muse_tqdm\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 29\u001b[0;31m \u001b[0mframe\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvr\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 30\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mseq_read_mmcv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0muse_tqdm\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/lib/python3.7/site-packages/decord-0.6.0-py3.7-linux-x86_64.egg/decord/video_reader.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, idx)\u001b[0m\n\u001b[1;32m 103\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mIndexError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Index: {} out of bound: {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0midx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_num_frame\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 104\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mseek_accurate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0midx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 105\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 106\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 107\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/lib/python3.7/site-packages/decord-0.6.0-py3.7-linux-x86_64.egg/decord/video_reader.py\u001b[0m in \u001b[0;36mnext\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 115\u001b[0m \"\"\"\n\u001b[1;32m 116\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_handle\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 117\u001b[0;31m \u001b[0marr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_CAPI_VideoReaderNextFrame\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_handle\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 118\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0marr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 119\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/lib/python3.7/site-packages/decord-0.6.0-py3.7-linux-x86_64.egg/decord/_ffi/_ctypes/function.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args)\u001b[0m\n\u001b[1;32m 173\u001b[0m check_call(_LIB.DECORDFuncCall(\n\u001b[1;32m 174\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhandle\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtcodes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mctypes\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mc_int\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum_args\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 175\u001b[0;31m ctypes.byref(ret_val), ctypes.byref(ret_tcode)))\n\u001b[0m\u001b[1;32m 176\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtemp_args\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 177\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.local/lib/python3.7/site-packages/decord-0.6.0-py3.7-linux-x86_64.egg/decord/_ffi/base.py\u001b[0m in \u001b[0;36mcheck_call\u001b[0;34m(ret)\u001b[0m\n\u001b[1;32m 76\u001b[0m \u001b[0merr_str\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0merr_str\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msplit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Stack trace'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstrip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 77\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mDECORDLimitReachedError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_str\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 78\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mDECORDError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_str\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 79\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 80\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mDECORDError\u001b[0m: [11:33:47] /content/decord/src/video/video_reader.cc:444: [big.mp4]Unable to handle EOF because it takes too long to retrieve last few frames and `DECORD_EOF_RETRY_MAX=10240`. You may override the limit by `export DECORD_EOF_RETRY_MAX=20480` for example to allow more EOF retry attempts, exit..."
]
}
],
"source": [
"seq_repeat = 5\n",
"random_repeat = 1\n",
"random_num = 100\n",
"path = \"big.mp4\"\n",
"print(f\"For big video: \")\n",
"print(f\"Sequential Read[{seq_repeat}x]:\")\n",
"print(f\"Decord GPU: {seq_read(seq_read_decord_gpu, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"Decord: {seq_read(seq_read_decord, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"MMCV: {seq_read(seq_read_mmcv, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"OpenCV: {seq_read(seq_read_cv2, path, seq_repeat, use_tqdm=True)}\")\n",
"print(f\"PyAV: {seq_read(seq_read_av, path, seq_repeat, use_tqdm=True)}\")"
]
},
{
"cell_type": "code",
"source": [
"import os\n",
"os.environ['DECORD_EOF_RETRY_MAX'] = \"20480\"\n",
"random_repeat = 1\n",
"random_num = 20\n",
"path = \"big.mp4\"\n",
"print(f\"Random Read[{random_repeat}x]:\")\n",
"print(f\"Decord GPU: {random_read(random_read_decord_gpu, path, random_repeat, random_num, use_tqdm=True)}\")\n",
"print(f\"Decord: {random_read(random_read_decord, path, random_repeat, random_num, use_tqdm=True)}\")\n",
"print(f\"MMCV: {random_read(random_read_mmcv, path, random_repeat, random_num, use_tqdm=True)}\")\n",
"print(f\"OpenCV: {random_read(random_read_cv2, path, random_repeat, random_num, use_tqdm=True)}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "0hiaQ2y1h4tZ",
"outputId": "64547c42-be3a-4f73-bcc7-0ef43e861fde"
},
"execution_count": 8,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Random Read[1x]:\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 20/20 [00:11<00:00, 1.74it/s]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord GPU: 12.417755365371704\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 20/20 [01:22<00:00, 4.12s/it]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Decord: 82.7718915939331\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 20/20 [02:02<00:00, 6.13s/it]\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"MMCV: 122.92250633239746\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"100%|██████████| 20/20 [01:45<00:00, 5.28s/it]"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"OpenCV: 105.77272725105286\n"
]
},
{
"output_type": "stream",
"name": "stderr",
"text": [
"\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"## Bug分析\n",
"\n",
"Decord有的时候会遇到奇奇怪怪的bug(如上),尤其是GPU版本。"
],
"metadata": {
"id": "xewGJujBkcSY"
}
},
{
"cell_type": "markdown",
"source": [
"## 总结\n",
"\n",
"假如要高效处理数据量大的视频,选用`Decord`的GPU版本。假如项目中其他地方会用到`mmcv`,那就用mmcv的VideoReader。其他情况假如想代码更易懂,则使用`Decord`,否则使用`OpenCV`。"
],
"metadata": {
"id": "X7F_7dDAmqxo"
}
},
{
"cell_type": "code",
"source": [],
"metadata": {
"id": "QmaRCGRLeih8"
},
"execution_count": null,
"outputs": []
}
],
"metadata": {
"colab": {
"collapsed_sections": [],
"name": "Benchmark of Video Reader in Python.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
},
"accelerator": "GPU",
"gpuClass": "standard"
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment