Commit ec01a239 authored by André Anjos's avatar André Anjos 💬
Browse files

Initial commit

parents
*~
*.swp
*.pyc
*.so
bin
eggs
parts
.installed.cfg
.mr.developer.cfg
*.egg-info
develop-eggs
sphinx
dist
.nfs*
.gdb_history
build
*.egg
src/
Copyright (c) 2013, Andre Anjos - Idiap Research Institute
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. Redistributions in binary
form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with
the distribution. Neither the name of the Idiap Research Institute nor the
names of its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include LICENSE README.rst bootstrap.py buildout.cfg
recursive-include doc conf.py *.rst
recursive-include xbob *.cpp *.h
recursive-include xbob/io/video/data *.*
.. vim: set fileencoding=utf-8 :
.. Andre Anjos <andre.anjos@idiap.ch>
.. Thu 29 Aug 2013 16:07:57 CEST
.. image:: https://travis-ci.org/bioidiap/xbob.io.video.svg?branch=master
:target: https://travis-ci.org/bioidiap/xbob.io.video
.. image:: https://coveralls.io/repos/bioidiap/xbob.io.video/badge.png
:target: https://coveralls.io/r/bioidiap/xbob.io.video
.. image:: http://img.shields.io/github/tag/bioidiap/xbob.io.video.png
:target: https://github.com/bioidiap/xbob.io.video
.. image:: http://img.shields.io/pypi/v/xbob.io.video.png
:target: https://pypi.python.org/pypi/xbob.io.video
.. image:: http://img.shields.io/pypi/dm/xbob.io.video.png
:target: https://pypi.python.org/pypi/xbob.io.video
==================================
Support for Video I/O in bob::io
==================================
This package contains support for Video I/O in Bob. Video reading and writing
is implemented using either FFmpeg or LibAV, whichever is installed.
Installation
------------
Install it through normal means, via PyPI or use ``zc.buildout`` to bootstrap
the package and run test units.
Documentation
-------------
You can generate the documentation for this package, after installation, using
Sphinx::
$ sphinx-build -b html doc sphinx
This shall place in the directory ``sphinx``, the current version for the
documentation of the package.
Usage
-----
In order to enable support for video file reading and writing in your
application, make sure to import this module, before calling
:py:func:`xbob.io.base.open` or similar::
>>> import xbob.io.base
>>> import xbob.io.video
>>> xbob.io.base.open('myfile.avi', 'r')
Testing
-------
You can run a set of tests using the nose test runner::
$ nosetests -sv xbob.io.video
.. warning::
If Bob <= 1.2.1 is installed on your python path, nose will automatically
load the old version of the insulate plugin available in Bob, which will
trigger the loading of incompatible shared libraries (from Bob itself), in
to your working binary. This will cause a stack corruption. Either remove
the centrally installed version of Bob, or build your own version of Python
in which Bob <= 1.2.1 is not installed.
You can run our documentation tests using sphinx itself::
$ sphinx-build -b doctest doc sphinx
You can test overall test coverage with::
$ nosetests --with-coverage --cover-package=xbob.io.video
The ``coverage`` egg must be installed for this to work properly.
Development
-----------
To develop this package, install using ``zc.buildout``, using the buildout
configuration found on the root of the package::
$ python bootstrap.py
...
$ ./bin/buildout
Tweak the options in ``buildout.cfg`` to disable/enable verbosity and debug
builds.
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Bootstrap a buildout-based project
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
"""
import os
import shutil
import sys
import tempfile
from optparse import OptionParser
tmpeggs = tempfile.mkdtemp()
usage = '''\
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
Bootstraps a buildout-based project.
Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use.
Note that by using --find-links to point to local resources, you can keep
this script from going over the network.
'''
parser = OptionParser(usage=usage)
parser.add_option("-v", "--version", help="use a specific zc.buildout version")
parser.add_option("-t", "--accept-buildout-test-releases",
dest='accept_buildout_test_releases',
action="store_true", default=False,
help=("Normally, if you do not specify a --version, the "
"bootstrap script and buildout gets the newest "
"*final* versions of zc.buildout and its recipes and "
"extensions for you. If you use this flag, "
"bootstrap and buildout will get the newest releases "
"even if they are alphas or betas."))
parser.add_option("-c", "--config-file",
help=("Specify the path to the buildout configuration "
"file to be used."))
parser.add_option("-f", "--find-links",
help=("Specify a URL to search for buildout releases"))
options, args = parser.parse_args()
######################################################################
# load/install setuptools
to_reload = False
try:
import pkg_resources
import setuptools
except ImportError:
ez = {}
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
# XXX use a more permanent ez_setup.py URL when available.
exec(urlopen('https://bitbucket.org/pypa/setuptools/raw/0.7.2/ez_setup.py'
).read(), ez)
setup_args = dict(to_dir=tmpeggs, download_delay=0)
ez['use_setuptools'](**setup_args)
if to_reload:
reload(pkg_resources)
import pkg_resources
# This does not (always?) update the default working set. We will
# do it.
for path in sys.path:
if path not in pkg_resources.working_set.entries:
pkg_resources.working_set.add_entry(path)
######################################################################
# Try to best guess the version of buildout given setuptools
if options.version is None:
try:
from distutils.version import LooseVersion
package = pkg_resources.require('setuptools')[0]
v = LooseVersion(package.version)
if v < LooseVersion('0.7'):
options.version = '2.1.1'
except:
pass
######################################################################
# Install buildout
ws = pkg_resources.working_set
cmd = [sys.executable, '-c',
'from setuptools.command.easy_install import main; main()',
'-mZqNxd', tmpeggs]
find_links = os.environ.get(
'bootstrap-testing-find-links',
options.find_links or
('http://downloads.buildout.org/'
if options.accept_buildout_test_releases else None)
)
if find_links:
cmd.extend(['-f', find_links])
setuptools_path = ws.find(
pkg_resources.Requirement.parse('setuptools')).location
requirement = 'zc.buildout'
version = options.version
if version is None and not options.accept_buildout_test_releases:
# Figure out the most recent final version of zc.buildout.
import setuptools.package_index
_final_parts = '*final-', '*final'
def _final_version(parsed_version):
for part in parsed_version:
if (part[:1] == '*') and (part not in _final_parts):
return False
return True
index = setuptools.package_index.PackageIndex(
search_path=[setuptools_path])
if find_links:
index.add_find_links((find_links,))
req = pkg_resources.Requirement.parse(requirement)
if index.obtain(req) is not None:
best = []
bestv = None
for dist in index[req.project_name]:
distv = dist.parsed_version
if _final_version(distv):
if bestv is None or distv > bestv:
best = [dist]
bestv = distv
elif distv == bestv:
best.append(dist)
if best:
best.sort()
version = best[-1].version
if version:
requirement = '=='.join((requirement, version))
cmd.append(requirement)
import subprocess
if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
raise Exception(
"Failed to execute command:\n%s",
repr(cmd)[1:-1])
######################################################################
# Import and run buildout
ws.add_entry(tmpeggs)
ws.require(requirement)
import zc.buildout.buildout
if not [a for a in args if '=' not in a]:
args.append('bootstrap')
# if -c was provided, we push it back into args for buildout' main function
if options.config_file is not None:
args[0:0] = ['-c', options.config_file]
zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)
; vim: set fileencoding=utf-8 :
; Andre Anjos <andre.anjos@idiap.ch>
; Mon 16 Apr 08:29:18 2012 CEST
[buildout]
parts = scripts
eggs = xbob.io.video
extensions = xbob.buildout
mr.developer
auto-checkout = *
develop = src/xbob.extension
src/xbob.blitz
src/xbob.io.base
.
; options for xbob.buildout extension
debug = true
verbose = true
prefixes = /idiap/group/torch5spro/nightlies/last/bob/linux-x86_64-release
/Users/andre/work/bob/b/dbg/
[sources]
xbob.extension = git https://github.com/bioidiap/xbob.extension branch=prototype
xbob.blitz = git https://github.com/bioidiap/xbob.blitz
xbob.io.base = fs xbob.io.base
[scripts]
recipe = xbob.buildout:scripts
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Andre Anjos <andre.anjos@idiap.ch>
# Mon 16 Apr 08:18:08 2012 CEST
from setuptools import setup, find_packages, dist
dist.Distribution(dict(setup_requires=['xbob.blitz', 'xbob.io.base']))
from xbob.blitz.extension import Extension
import xbob.io.base
include_dirs = [xbob.io.base.get_include()]
packages = [
'bob-io >= 2.0.0a2',
'libavformat >= 52.31.0',
'libavcodec >= 52.20.0',
'libavutil >= 49.15.0',
'libswscale >= 0.7.1'
]
version = '2.0.0a0'
setup(
name='xbob.io.video',
version=version,
description='Video I/O support for Bob',
url='http://github.com/bioidiap/xbob.io.video',
license='BSD',
author='Andre Anjos',
author_email='andre.anjos@idiap.ch',
long_description=open('README.rst').read(),
packages=find_packages(),
include_package_data=True,
install_requires=[
'setuptools',
'xbob.blitz',
'xbob.io.base',
],
namespace_packages=[
"xbob",
"xbob.io",
],
ext_modules = [
Extension("xbob.io.video.version",
[
"xbob/io/video/version.cpp",
],
packages = packages,
include_dirs = include_dirs,
version = version,
define_macros = [('__STDC_CONSTANT_MACROS', None)],
),
Extension("xbob.io.video._library",
[
"xbob/io/video/cpp/utils.cpp",
"xbob/io/video/cpp/reader.cpp",
"xbob/io/video/cpp/writer.cpp",
"xbob/io/video/reader.cpp",
"xbob/io/video/writer.cpp",
"xbob/io/video/file.cpp",
"xbob/io/video/main.cpp",
],
packages = packages,
include_dirs = include_dirs,
version = version,
define_macros = [('__STDC_CONSTANT_MACROS', None)],
),
],
entry_points={
'console_scripts': [
'xbob_video_test.py = xbob.io.script.video_test:main',
],
},
classifiers = [
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Natural Language :: English',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries :: Python Modules',
'Environment :: Plugins',
],
)
#see http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
__import__('pkg_resources').declare_namespace(__name__)
#see http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
__import__('pkg_resources').declare_namespace(__name__)
from ._library import reader, writer
from . import version
from .version import module as __version__
def get_config():
"""Returns a string containing the configuration information.
"""
import pkg_resources
from .version import externals
packages = pkg_resources.require(__name__)
this = packages[0]
deps = packages[1:]
retval = "%s: %s (%s)\n" % (this.key, this.version, this.location)
retval += " - c/c++ dependencies:\n"
for k in sorted(externals): retval += " - %s: %s\n" % (k, externals[k])
retval += " - python dependencies:\n"
for d in deps: retval += " - %s: %s (%s)\n" % (d.key, d.version, d.location)
return retval.strip()
# gets sphinx autodoc done right - don't remove it
__all__ = [_ for _ in dir() if not _.startswith('_')]
/**
* @file io/cxx/video::Reader.cc
* @date Wed Jun 22 17:50:08 2011 +0200
* @author Andre Anjos <andre.anjos@idiap.ch>
*
* @brief A class to help you read videos. This code originates from
* http://ffmpeg.org/doxygen/1.0/, "decoding & encoding example".
*
* Copyright (C) Idiap Research Institute, Martigny, Switzerland
*/
#include "reader.h"
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/preprocessor.hpp>
#include <limits>
#include <bob/core/check.h>
#include <bob/core/blitz_array.h>
#ifndef AV_PIX_FMT_RGB24
#define AV_PIX_FMT_RGB24 PIX_FMT_RGB24
#endif
namespace bob::io::video {
Reader::Reader(const std::string& filename, bool check) {
open(filename, check);
}
Reader::Reader(const Reader& other) {
*this = other;
}
Reader& Reader::operator= (const Reader& other) {
open(other.filename(), other.m_check);
return *this;
}
void Reader::open(const std::string& filename, bool check) {
m_filepath = filename;
boost::shared_ptr<AVFormatContext> format_ctxt =
make_input_format_context(m_filepath);
m_formatname = format_ctxt->iformat->name;
m_formatname_long = format_ctxt->iformat->long_name;
int stream_index = find_video_stream(m_filepath, format_ctxt);
AVCodec* codec = find_decoder(m_filepath, format_ctxt, stream_index);
m_codecname = codec->name;
m_codecname_long = codec->long_name;
/**
* Runs a format/codec check on user request
*/
if (check) {
if (!iformat_is_supported(m_formatname)) {
boost::format s("The detected format (`%s' = `%s') of the input video file `%s' is not currently supported by this version of Bob. Convert the video file to a supported wrapping format or disable the `check' flag on the video::Reader object (if you are sure of what you are doing).");
s % m_formatname % m_formatname_long % m_filepath;
throw std::runtime_error(s.str());
}
if (!codec_is_supported(m_codecname)) {
boost::format s("The detected decoder (`%s' = `%s') for the video stream on the input video file `%s' is not currently supported by this version of Bob. Convert the video file to a supported codec or disable the `check' flag on the video::Reader object (if you are sure of what you are doing).");
s % m_codecname % m_codecname_long % m_filepath;
throw std::runtime_error(s.str());
}
}
boost::shared_ptr<AVCodecContext> codec_ctxt =
make_codec_context(m_filepath,
format_ctxt->streams[stream_index], codec);
/**
* Copies some information from the context just opened
*/
m_width = codec_ctxt->width;
m_height = codec_ctxt->height;
m_duration = format_ctxt->duration;
m_nframes = format_ctxt->streams[stream_index]->nb_frames;
if (m_nframes > 0) {
//number of frames is known
m_framerate = (double(m_nframes) * AV_TIME_BASE) / double(m_duration);
}
else {
//number of frames is not known
m_framerate = av_q2d(format_ctxt->streams[stream_index]->r_frame_rate);
m_nframes = (int)(m_framerate * m_duration / AV_TIME_BASE);
}
/**
* This will create a local description of the contents of the stream, in
* printable format.
*/
boost::format fmt("Video file: %s; FFmpeg: avformat-%s; avcodec-%s; avutil-%s; swscale-%d; Format: %s (%s); Codec: %s (%s); Time: %.2f s (%d @ %2.fHz); Size (w x h): %d x %d pixels");
fmt % m_filepath;
fmt % BOOST_PP_STRINGIZE(LIBAVFORMAT_VERSION);
fmt % BOOST_PP_STRINGIZE(LIBAVCODEC_VERSION);
fmt % BOOST_PP_STRINGIZE(LIBAVUTIL_VERSION);
fmt % BOOST_PP_STRINGIZE(LIBSWSCALE_VERSION);
fmt % m_formatname_long;
fmt % m_formatname;
fmt % m_codecname_long;
fmt % m_codecname;
fmt % (m_duration / 1e6);
fmt % m_nframes;
fmt % m_framerate;
fmt % m_width;
fmt % m_height;
m_formatted_info = fmt.str();
/**
* This will make sure we can interface with the io subsystem
*/
m_typeinfo_video.dtype = m_typeinfo_frame.dtype = bob::core::array::t_uint8;
m_typeinfo_video.nd = 4;
m_typeinfo_frame.nd = 3;
m_typeinfo_video.shape[0] = m_nframes;
m_typeinfo_video.shape[1] = m_typeinfo_frame.shape[0] = 3;
m_typeinfo_video.shape[2] = m_typeinfo_frame.shape[1] = m_height;
m_typeinfo_video.shape[3] = m_typeinfo_frame.shape[2] = m_width;
m_typeinfo_frame.update_strides();
m_typeinfo_video.update_strides();
}
Reader::~Reader() {
}
size_t Reader::load(blitz::Array<uint8_t,4>& data,
bool throw_on_error, void (*check)(void)) const {
bob::core::array::blitz_array tmp(data);
return load(tmp, throw_on_error, check);
}
size_t Reader::load(bob::core::array::interface& b,
bool throw_on_error, void (*check)(void)) const {
//checks if the output array shape conforms to the video specifications,
//otherwise, throw.
if (!m_typeinfo_video.is_compatible(b.type())) {
boost::format s("input buffer (%s) does not conform to the video size specifications (%s)");
s % b.type().str() % m_typeinfo_video.str();
throw std::runtime_error(s.str());
}
unsigned long int frame_size = m_typeinfo_frame.buffer_size();
uint8_t* ptr = static_cast<uint8_t*>(b.ptr());
size_t frames_read = 0;