Skip to content
This repository has been archived by the owner on Oct 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #2 from mitmul/use-stream
Browse files Browse the repository at this point in the history
Use stream
  • Loading branch information
mitmul authored May 5, 2018
2 parents 8d84a40 + fe8852b commit 95cd26e
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 75 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
PyNVVL
======
[![pypi-pynvvl-cuda80](https://img.shields.io/pypi/v/pynvvl-cuda80.svg)](https://pypi.org/project/pynvvl-cuda80)]
[![pypi-pynvvl-cuda90](https://img.shields.io/pypi/v/pynvvl-cuda90.svg)](https://pypi.org/project/pynvvl-cuda90)]
[![pypi-pynvvl-cuda91](https://img.shields.io/pypi/v/pynvvl-cuda91.svg)](https://pypi.org/project/pynvvl-cuda91)]
[![GitHub license](https://img.shields.io/github/license/mitmul/pynvvl.svg)](https://github.com/mitmul/pynvvl)

PyNVVL is a thin wrapper of [NVIDIA Video Loader (NVVL)](https://github.com/NVIDIA/nvvl). This package enables you to load videos directoly to GPU memory and access them as [CuPy](https://github.com/cupy/cupy) ndarrays with zero copy.

Expand Down Expand Up @@ -118,9 +122,5 @@ Loads the video from disk and returns it as a CuPy ndarray.
- nvidia-docker (v1/v2)

```
bash docker/build_docker.sh
sudo rm -rf docker/lib
bash docker/build_nvvl.sh
sudo rm -rf build dist *.egg-info
python docker/build_wheels.py
bash docker/build_wheels.sh
```
9 changes: 7 additions & 2 deletions docker/Dockerfile.develop
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ RUN apt-get update && apt-get install -y \
python3-dev \
python3-pip \
python3-tk \
gawk
python3-dbg \
ffmpeg \
gdb \
gawk \
chrpath

RUN pip3 install \
cython \
numpy \
matplotlib
matplotlib \
imageio

ARG CUPY_PACKAGE_NAME
RUN pip3 install ${CUPY_PACKAGE_NAME}
2 changes: 0 additions & 2 deletions docker/build_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ build_docker_image() {
docker build -t mitmul/pynvvl:cuda-$1 \
--build-arg CUDA_VERSION=$1 \
-f docker/Dockerfile.build-nvvl docker
docker push mitmul/pynvvl:cuda-$1

docker build -t mitmul/pynvvl:cuda-$1-dev \
--build-arg CUDA_VERSION=$1 \
--build-arg CUPY_PACKAGE_NAME=$2 \
-f docker/Dockerfile.develop docker
docker push mitmul/pynvvl:cuda-$1-dev
}

build_docker_image 8.0 cupy-cuda80
Expand Down
6 changes: 4 additions & 2 deletions docker/build_wheels.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

CYTHON_VERSION = '0.27.3'
CUPY_VERSION = '4.0.0'
PYNVVL_VERSION = '0.0.2a1'
PYNVVL_VERSION = '0.0.2a2'

WHEEL_CONFIGS = {
'8.0': {
Expand Down Expand Up @@ -141,7 +141,9 @@ def build_wheels(cuda_version):
pyenv global {python_version} && pyenv rehash && \
pip install /wheels/{wheel_name} && \
cd / && python examples/simple_load.py \
> /examples/cuda-{cuda_version}_python-{python_version}.txt \
> /examples/cuda-{cuda_version}_python-{python_version}.txt && \
mv /examples/sample.png \
/examples/sample_cuda-{cuda_version}_python-{python_version}.png \
"'.format(
source_dir=os.getcwd(),
tag=WHEEL_CONFIGS[cuda_version]['test'],
Expand Down
8 changes: 8 additions & 0 deletions docker/build_wheels.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

bash docker/build_docker.sh
sudo rm -rf docker/lib
bash docker/build_nvvl.sh
sudo rm -rf build dist *.egg-info
sudo rm -rf examples/*.txt examples/*.png
python3 docker/build_wheels.py
2 changes: 1 addition & 1 deletion docker/enter_devenv.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ cd /root/nvvl/build && \
cmake ../ \
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
-DCMAKE_INSTALL_RPATH=\"\\\$ORIGIN\" && \
apt-get install chrpath && \
make -j && chrpath -l libnvvl.so && \
cd /root/pynvvl && \
bash
"
30 changes: 30 additions & 0 deletions examples/check_performance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import glob
import os
import time

import imageio
import numpy as np

import pynvvl

video_fn = 'examples/sample.mp4'
N = 100

loader = pynvvl.NVVLVideoLoader(0)

time_pynvvl = []
for _ in range(N):
st = time.time()
video = loader.read_sequence(video_fn)
time_pynvvl.append(time.time() - st)
print('PyNVVL: {} sec'.format(np.mean(time_pynvvl)))

time_imageio = []
for _ in range(N):
st = time.time()
video = imageio.mimread(video_fn)
time_imageio.append(time.time() - st)
print('ImageIO: {} sec'.format(np.mean(time_imageio)))
2 changes: 1 addition & 1 deletion pynvvl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


__copyright__ = 'Copyright (C) 2018 Shunta Saito'
__version__ = '0.0.2a1'
__version__ = '0.0.2a2'
__license__ = 'MIT License'
__author__ = 'Shunta Saito'
__author_email__ = 'shunta.saito@gmail.com'
Expand Down
138 changes: 77 additions & 61 deletions pynvvl/_nvvl.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,27 @@ from libc.stdint cimport uint16_t
from libc.stdint cimport uint8_t


cdef extern from "cuda_runtime.h":

cdef struct CUstream_st
ctypedef CUstream_st* cudaStream_t


cdef extern from "PictureSequence.h":

ctypedef void* PictureSequenceHandle

cdef PictureSequenceHandle nvvl_create_sequence(uint16_t count)

cdef void nvvl_set_layer(
PictureSequenceHandle sequence,
const NVVL_PicLayer* layer,
const char* name)

cdef void nvvl_sequence_stream_wait(
PictureSequenceHandle sequence,
cudaStream_t stream)

cdef void nvvl_free_sequence(PictureSequenceHandle sequence)

enum NVVL_ScaleMethod:
Expand Down Expand Up @@ -69,13 +82,19 @@ cdef extern from "PictureSequence.h":
cdef extern from "VideoLoader.h":

ctypedef void* VideoLoaderHandle

cdef VideoLoaderHandle nvvl_create_video_loader(int device_id)

cdef void nvvl_destroy_video_loader(VideoLoaderHandle loader)

cdef int nvvl_frame_count(VideoLoaderHandle loader, const char* filename)

cdef void nvvl_read_sequence(
VideoLoaderHandle loader, const char* filename, int frame, int count)

cdef PictureSequenceHandle nvvl_receive_frames(
VideoLoaderHandle loader, PictureSequenceHandle sequence);

cdef PictureSequenceHandle nvvl_receive_frames_sync(
VideoLoaderHandle loader, PictureSequenceHandle sequence);

Expand Down Expand Up @@ -153,72 +172,69 @@ cdef class NVVLVideoLoader:
raise ValueError(
'count should be less than the video length ({}) '
'but {} was given.'.format(frame_count, count))
cdef PictureSequenceHandle sequence = nvvl_create_sequence(count)

cdef PictureSequenceHandle sequence = nvvl_create_sequence(count)
cdef Size size = nvvl_video_size(self.handle)
cdef uint16_t width = size.width if crop_width is None else crop_width
cdef uint16_t height = size.height if crop_height is None else crop_height
cdef NVVL_PicLayer layer
cdef string name = 'pixels'.encode('utf-8')

with cupy.cuda.Device(self.device_id) as d:
with cupy.cuda.Stream() as stream:
array = cupy.empty(
(count, channels, height, width), dtype=cupy.float32)
array = cupy.ascontiguousarray(array)
d.synchronize()

cdef NVVL_PicLayer layer
layer.type = PDT_FLOAT
layer.data = <void*><size_t>array.data.ptr
layer.index_map = NULL
layer.desc.count = count
layer.desc.channels = channels
layer.desc.height = height
layer.desc.width = width
layer.desc.crop_x = crop_x
layer.desc.crop_y = crop_y
layer.desc.scale_height = scale_height
layer.desc.scale_width = scale_width
layer.desc.horiz_flip = horiz_flip
layer.desc.normalized = normalized

cdef NVVL_ColorSpace nvvl_color_space
if color_space == 'RGB':
nvvl_color_space = ColorSpace_RGB
elif color_space == 'YCbCr':
nvvl_color_space = ColorSpace_YCbCr
else:
raise ValueError(
'color_space should be either \'RGB\' or \'YCbCr\' '
'but {} was given.'.format(color_space))
layer.desc.color_space = nvvl_color_space

cdef NVVL_ChromaUpMethod nvvl_chroma_up_method
if chroma_up_method == 'Linear':
nvvl_chroma_up_method = ChromaUpMethod_Linear
else:
raise ValueError(
'chroma_up_method should be \'Linear\' '
'but {} was given.'.format(chroma_up_method))
layer.desc.chroma_up_method = nvvl_chroma_up_method

cdef NVVL_ScaleMethod nvvl_scale_method
if scale_method == 'Nearest':
nvvl_scale_method = ScaleMethod_Nearest
elif scale_method == 'Linear':
nvvl_scale_method = ScaleMethod_Linear
else:
raise ValueError(
'scale_method should either \'Nearest\' or \'Linear\' '
'but {} was given.'.format(scale_method))
layer.desc.scale_method = nvvl_scale_method

layer.desc.stride.x = 1
layer.desc.stride.y = width * layer.desc.stride.x
layer.desc.stride.c = layer.desc.stride.y * height
layer.desc.stride.n = layer.desc.stride.c * channels

cdef string name = 'pixels'.encode('utf-8')
nvvl_set_layer(sequence, &layer, name.c_str())
nvvl_read_sequence(self.handle, filename.encode('utf-8'), frame, count)
nvvl_receive_frames_sync(self.handle, sequence)
nvvl_free_sequence(sequence)
return array
stream.synchronize()

layer.type = PDT_FLOAT
layer.data = <void*><size_t>array.data.ptr
layer.index_map = NULL
layer.desc.count = count
layer.desc.channels = channels
layer.desc.height = height
layer.desc.width = width
layer.desc.crop_x = crop_x
layer.desc.crop_y = crop_y
layer.desc.scale_height = scale_height
layer.desc.scale_width = scale_width
layer.desc.horiz_flip = horiz_flip
layer.desc.normalized = normalized

if color_space == 'RGB':
layer.desc.color_space = ColorSpace_RGB
elif color_space == 'YCbCr':
layer.desc.color_space = ColorSpace_YCbCr
else:
raise ValueError(
'color_space should be either \'RGB\' or \'YCbCr\' '
'but {} was given.'.format(color_space))

if chroma_up_method == 'Linear':
layer.desc.chroma_up_method = ChromaUpMethod_Linear
else:
raise ValueError(
'chroma_up_method should be \'Linear\' '
'but {} was given.'.format(chroma_up_method))

if scale_method == 'Nearest':
layer.desc.scale_method = ScaleMethod_Nearest
elif scale_method == 'Linear':
layer.desc.scale_method = ScaleMethod_Linear
else:
raise ValueError(
'scale_method should either \'Nearest\' or \'Linear\' '
'but {} was given.'.format(scale_method))

layer.desc.stride.x = 1
layer.desc.stride.y = width * layer.desc.stride.x
layer.desc.stride.c = layer.desc.stride.y * height
layer.desc.stride.n = layer.desc.stride.c * channels

stream.record()
nvvl_set_layer(sequence, &layer, name.c_str())
nvvl_read_sequence(self.handle, filename.encode('utf-8'), frame, count)
nvvl_receive_frames(self.handle, sequence)
nvvl_sequence_stream_wait(
sequence, <cudaStream_t><size_t>stream.ptr)
nvvl_free_sequence(sequence)
return array
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,16 @@ def prepare_package_data():
print('CuPy Package Name:', cupy_package_name)
print('=' * 30)

description = \
'PyNVVL: A Python wrapper for NVIDIA Video Loader (NVVL) with CuPy'

setup(
name=args.package_name,
url='https://github.com/mitmul/pynvvl',
version='0.0.2a1',
version='0.0.2a2',
author='Shunta Saito',
author_email='shunta.saito@gmail.com',
description=description,
license='MIT License',
packages=['pynvvl'],
package_data=package_data,
Expand Down

0 comments on commit 95cd26e

Please sign in to comment.