diff --git a/CMakeLists.txt b/CMakeLists.txt index 76ea1fc66..51ebbec26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ OPTION(BUILD_OPENNI2_DRIVER "Build OpenNI2 driver" ON) OPTION(ENABLE_CXX11 "Enable C++11 support" OFF) OPTION(ENABLE_OPENCL "Enable OpenCL support" ON) OPTION(ENABLE_OPENGL "Enable OpenGL support" ON) +OPTION(ENABLE_VAAPI "Enable VA-API support" ON) IF(MSVC) # suppress several "possible loss of data" warnings, and @@ -44,6 +45,7 @@ ELSE() SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") ENDIF() +SET(HAVE_CXX11 disabled) IF(ENABLE_CXX11) INCLUDE(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) @@ -51,9 +53,12 @@ IF(ENABLE_CXX11) IF(COMPILER_SUPPORTS_CXX11) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") SET(LIBFREENECT2_WITH_CXX11_SUPPORT 1) + SET(HAVE_CXX11 yes) ELSEIF(COMPILER_SUPPORTS_CXX0X) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + SET(HAVE_CXX11 c++0x) ELSE() + SET(HAVE_CXX11 no) MESSAGE(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") ENDIF() ENDIF(ENABLE_CXX11) @@ -103,7 +108,7 @@ SET(SOURCES include/internal/libfreenect2/async_packet_processor.h include/internal/libfreenect2/depth_packet_processor.h include/internal/libfreenect2/depth_packet_stream_parser.h - include/internal/libfreenect2/double_buffer.h + include/internal/libfreenect2/allocator.h include/libfreenect2/frame_listener.hpp include/libfreenect2/frame_listener_impl.h include/libfreenect2/libfreenect2.hpp @@ -118,7 +123,7 @@ SET(SOURCES src/transfer_pool.cpp src/event_loop.cpp src/usb_control.cpp - src/double_buffer.cpp + src/allocator.cpp src/frame_listener_impl.cpp src/packet_pipeline.cpp src/rgb_packet_stream_parser.cpp @@ -147,11 +152,14 @@ SET(LIBFREENECT2_DLLS ${LibUSB_DLL} ) +SET(HAVE_VideoToolbox "no (Apple only)") IF(APPLE) FIND_LIBRARY(VIDEOTOOLBOX_LIBRARY VideoToolbox) + SET(HAVE_VideoToolbox no) IF(VIDEOTOOLBOX_LIBRARY) SET(LIBFREENECT2_WITH_VT_SUPPORT 1) + SET(HAVE_VideoToolbox yes) FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED) FIND_LIBRARY(COREMEDIA_LIBRARY CoreMedia REQUIRED) @@ -170,14 +178,41 @@ IF(APPLE) ENDIF(VIDEOTOOLBOX_LIBRARY) ENDIF(APPLE) +SET(HAVE_VAAPI disabled) +IF(ENABLE_VAAPI) + IF(PKG_CONFIG_FOUND) + PKG_CHECK_MODULES(VAAPI libva libva-drm) + ENDIF() + FIND_PACKAGE(JPEG) + + SET(HAVE_VAAPI no) + IF(VAAPI_FOUND AND JPEG_FOUND) + SET(LIBFREENECT2_WITH_VAAPI_SUPPORT 1) + SET(HAVE_VAAPI yes) + + INCLUDE_DIRECTORIES(${VAAPI_INCLUDE_DIRS}) + + LIST(APPEND SOURCES + src/vaapi_rgb_packet_processor.cpp + ) + LIST(APPEND LIBRARIES + ${VAAPI_LIBRARIES} + ${JPEG_LIBRARY} + ) + ENDIF() +ENDIF(ENABLE_VAAPI) + IF(LIBFREENECT2_WITH_VT_SUPPORT) FIND_PACKAGE(TurboJPEG) ELSE() + # VAAPI can fail to start at runtime. It must have a fallback. FIND_PACKAGE(TurboJPEG REQUIRED) ENDIF() +SET(HAVE_TurboJPEG no) IF(TurboJPEG_FOUND) SET(LIBFREENECT2_WITH_TURBOJPEG_SUPPORT 1) + SET(HAVE_TurboJPEG yes) INCLUDE_DIRECTORIES(${TurboJPEG_INCLUDE_DIRS}) @@ -192,13 +227,17 @@ IF(TurboJPEG_FOUND) LIST(APPEND LIBFREENECT2_DLLS ${TurboJPEG_DLL} ) - ENDIF() +SET(HAVE_OpenGL disablsed) IF(ENABLE_OPENGL) FIND_PACKAGE(GLFW3) FIND_PACKAGE(OpenGL) - IF(GLFW3_FOUND) + SET(HAVE_OpenGL no) + IF(GLFW3_FOUND AND OPENGL_FOUND) + SET(LIBFREENECT2_WITH_OPENGL_SUPPORT 1) + SET(HAVE_OpenGL yes) + INCLUDE_DIRECTORIES(${GLFW3_INCLUDE_DIRS}) LIST(APPEND LIBFREENECT2_DLLS ${GLFW3_DLL}) @@ -206,35 +245,39 @@ IF(ENABLE_OPENGL) ${GLFW3_LIBRARIES} ${OPENGL_gl_LIBRARY} ) - SET(LIBFREENECT2_WITH_OPENGL_SUPPORT 1) - LIST(APPEND SOURCES - src/flextGL.cpp - src/opengl_depth_packet_processor.cpp - ) + LIST(APPEND SOURCES + src/flextGL.cpp + src/opengl_depth_packet_processor.cpp + ) - LIST(APPEND RESOURCES - src/shader/debug.fs - src/shader/default.vs - src/shader/filter1.fs - src/shader/filter2.fs - src/shader/stage1.fs - src/shader/stage2.fs - ) + LIST(APPEND RESOURCES + src/shader/debug.fs + src/shader/default.vs + src/shader/filter1.fs + src/shader/filter2.fs + src/shader/stage1.fs + src/shader/stage2.fs + ) ENDIF() ENDIF(ENABLE_OPENGL) +SET(HAVE_OpenCL disablsed) IF(ENABLE_OPENCL) FIND_PACKAGE(OpenCL) + SET(HAVE_OpenCL no) IF(OpenCL_FOUND) + SET(LIBFREENECT2_WITH_OPENCL_SUPPORT 1) + SET(HAVE_OpenCL yes) + IF(UNIX AND NOT APPLE) INCLUDE(CheckOpenCLICDLoader) IF(OpenCL_C_WORKS AND NOT OpenCL_CXX_WORKS) SET(LIBFREENECT2_OPENCL_ICD_LOADER_IS_OLD 1) + SET(HAVE_OpenCL "yes but buggy") MESSAGE(WARNING "Your libOpenCL.so is incompatible with CL/cl.h. Install ocl-icd-opencl-dev to update libOpenCL.so?") ENDIF() ENDIF() - SET(LIBFREENECT2_WITH_OPENCL_SUPPORT 1) INCLUDE_DIRECTORIES(${OpenCL_INCLUDE_DIRS}) LIST(APPEND SOURCES @@ -312,14 +355,19 @@ INSTALL(FILES "${PROJECT_BINARY_DIR}/freenect2.pc" DESTINATION lib/pkgconfig/) ADD_SUBDIRECTORY(${MY_DIR}/doc) +SET(HAVE_Examples disablsed) IF(BUILD_EXAMPLES) + SET(HAVE_Examples yes) MESSAGE(STATUS "Configurating examples") ADD_SUBDIRECTORY(${MY_DIR}/examples) ENDIF() +SET(HAVE_OpenNI2 disablsed) IF(BUILD_OPENNI2_DRIVER) FIND_PACKAGE(OpenNI2) + SET(HAVE_OpenNI2 no) IF(OpenNI2_FOUND) + SET(HAVE_OpenNI2 yes) FILE(GLOB OPENNI2_DRIVER_SOURCES src/openni2/*.cpp) ADD_LIBRARY(freenect2-openni2 ${OPENNI2_DRIVER_SOURCES} ${LIBFREENECT2_THREADING_SOURCE}) TARGET_INCLUDE_DIRECTORIES(freenect2-openni2 PRIVATE ${OpenNI2_INCLUDE_DIRS}) @@ -336,3 +384,12 @@ IF(BUILD_OPENNI2_DRIVER) ) ENDIF() ENDIF() + +GET_CMAKE_PROPERTY(vars VARIABLES) +MESSAGE(STATUS "Feature list:") +FOREACH(var ${vars}) + IF(var MATCHES ^HAVE_) + STRING(REPLACE HAVE_ "" feature ${var}) + MESSAGE(STATUS " ${feature} ${${var}}") + ENDIF() +ENDFOREACH() diff --git a/README.md b/README.md index dbbebf105..b81f067b5 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ It has been reported to work for up to 5 devices on a high-end PC using multiple * OpenGL depth processing: OpenGL 3.1 (Windows, Linux, Mac OS X). OpenGL ES is not supported at the moment. * OpenCL depth processing: OpenCL 1.1 +* VAAPI JPEG decoding: Intel and Linux only * OpenNI2 integration: OpenNI2 2.2.0.33 ## Troubleshooting and reporting bugs @@ -216,6 +217,10 @@ sudo apt-get install build-essential cmake pkg-config - Nvidia discrete/Intel integrated GPUs: this gets tricky, but the rule of thumb is to make sure the actually used OpenCL headers and the driver libraries have matching versions. - Mali GPU (e.g. Odroid XU4): (with root) `mkdir -p /etc/OpenCL/vendors; echo /usr/lib/arm-linux-gnueabihf/mali-egl/libmali.so >/etc/OpenCL/vendors/mali.icd; apt-get install opencl-headers`. - Verify: You can install `clinfo` to verify if you have correctly set up the OpenCL stack. +* Install VAAPI (optional, Intel only) + 1. (Ubuntu 14.04 only) `sudo dpkg -i debs/{libva,i965}*deb; sudo apt-get install -f` + 2. (Other) `sudo apt-get install libva-dev libjpeg-dev` + 3. Linux kernels 4.1 to 4.3 have performance regression. Use 4.0 and earlier or 4.4 and later (Though Ubuntu kernel 4.2.0-28.33~14.04.1 has backported the fix). * Install OpenNI2 (optional) 1. (Ubuntu 14.04 only) `sudo apt-add-repository ppa:deb-rob/ros-trusty && sudo apt-get update` (You don't need this if you have ROS repos), then `sudo apt-get install libopenni2-dev` 2. (Other) `sudo apt-get install libopenni2-dev`. diff --git a/cmake_modules/SetupLibfreenect2Threading.cmake b/cmake_modules/SetupLibfreenect2Threading.cmake index e4c43e0cd..d08057994 100644 --- a/cmake_modules/SetupLibfreenect2Threading.cmake +++ b/cmake_modules/SetupLibfreenect2Threading.cmake @@ -27,6 +27,7 @@ IF(LIBFREENECT2_THREADING_STDLIB) SET(LIBFREENECT2_THREADING_SOURCE "") SET(LIBFREENECT2_THREADING_LIBRARIES "") SET(LIBFREENECT2_THREADING_STDLIB 1) + SET(HAVE_Threading std::thread) ELSE(LIBFREENECT2_THREADING_STDLIB) SET(LIBFREENECT2_THREADING "tinythread") SET(LIBFREENECT2_THREADING_INCLUDE_DIR "src/tinythread/") @@ -37,6 +38,7 @@ ELSE(LIBFREENECT2_THREADING_STDLIB) SET(LIBFREENECT2_THREADING_LIBRARIES "") ENDIF(NOT WIN32) SET(LIBFREENECT2_THREADING_TINYTHREAD 1) + SET(HAVE_Threading tinythread) ENDIF(LIBFREENECT2_THREADING_STDLIB) MESSAGE(STATUS "using ${LIBFREENECT2_THREADING} as threading library") diff --git a/include/internal/libfreenect2/allocator.h b/include/internal/libfreenect2/allocator.h new file mode 100644 index 000000000..e7b1bbc4a --- /dev/null +++ b/include/internal/libfreenect2/allocator.h @@ -0,0 +1,96 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2014 individual OpenKinect contributors. See the CONTRIB file + * for details. + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +/** @file allocator.h Allocator definitions. */ + +#ifndef ALLOCATOR_H_ +#define ALLOCATOR_H_ + +#include + +namespace libfreenect2 +{ + +class Buffer +{ +public: + size_t capacity; ///< Capacity of the buffer. + size_t length; ///< Used length of the buffer. + unsigned char* data; ///< Start address of the buffer. +}; + +class Allocator +{ +public: + /* If the inner allocator fails to allocate, it MUST not return NULL. + * Instead it MUST return a Buffer with data being NULL. + * The stdlib will throw std::bad_alloc if new Buffer fails. + */ + virtual Buffer *allocate(size_t size) = 0; + virtual void free(Buffer *b) = 0; + virtual ~Allocator() {} +}; + +class PoolAllocatorImpl; + +class PoolAllocator: public Allocator +{ +public: + /* Use new as the inner allocator. */ + PoolAllocator(); + + /* This inner allocator will be freed by PoolAllocator. */ + PoolAllocator(Allocator *inner); + + virtual ~PoolAllocator(); + + /* allocate() will block until an allocation is possible. + * It should be called as late as possible before the memory is required + * for write access. + * + * This allocate() never returns NULL as required by Allocator. + * + * All calls to allocate() MUST have the same size. + * + * allocate() MUST be called from the same thread. + */ + virtual Buffer *allocate(size_t size); + + /* free() will unblock pending allocation. + * It should be called as early as possible after the memory is no longer + * required for read access. + * + * The inner free() can be called with NULL. + * + * free() can be called from different threads than allocate(). + */ + virtual void free(Buffer *b); +private: + PoolAllocatorImpl *impl_; +}; + +} /* namespace libfreenect2 */ +#endif /* ALLOCATOR_H_ */ diff --git a/include/internal/libfreenect2/async_packet_processor.h b/include/internal/libfreenect2/async_packet_processor.h index 5e7d03a76..2ccb7ca2d 100644 --- a/include/internal/libfreenect2/async_packet_processor.h +++ b/include/internal/libfreenect2/async_packet_processor.h @@ -78,6 +78,11 @@ class AsyncPacketProcessor : public PacketProcessor return locked; } + virtual bool good() + { + return processor_->good(); + } + virtual void process(const PacketT &packet) { { @@ -87,6 +92,17 @@ class AsyncPacketProcessor : public PacketProcessor } packet_condition_.notify_one(); } + + virtual void allocateBuffer(PacketT &p, size_t size) + { + processor_->allocateBuffer(p, size); + } + + virtual void releaseBuffer(PacketT &p) + { + processor_->releaseBuffer(p); + } + private: PacketProcessorPtr processor_; ///< The processing routine, executed in the asynchronous thread. bool current_packet_available_; ///< Whether #current_packet_ still needs processing. @@ -119,6 +135,15 @@ class AsyncPacketProcessor : public PacketProcessor { // invoke process impl processor_->process(current_packet_); + /* + * The stream parser passes the buffer asynchronously to processors so + * it can not wait after process() finishes and free the buffer. In + * theory releaseBuffer() should be called as soon as the access to it + * is finished, but right now no new allocateBuffer() will be called + * before ready() becomes true, so releaseBuffer() in the main loop of + * the async processor is OK. + */ + releaseBuffer(current_packet_); current_packet_available_ = false; } diff --git a/include/internal/libfreenect2/depth_packet_processor.h b/include/internal/libfreenect2/depth_packet_processor.h index 9889444ae..68bf6a10b 100644 --- a/include/internal/libfreenect2/depth_packet_processor.h +++ b/include/internal/libfreenect2/depth_packet_processor.h @@ -47,6 +47,8 @@ struct DepthPacket uint32_t timestamp; unsigned char *buffer; ///< Depth data. size_t buffer_length; ///< Size of depth data. + + Buffer *memory; }; /** Class for processing depth information. */ diff --git a/include/internal/libfreenect2/depth_packet_stream_parser.h b/include/internal/libfreenect2/depth_packet_stream_parser.h index b0013b6b5..2db3c4f7c 100644 --- a/include/internal/libfreenect2/depth_packet_stream_parser.h +++ b/include/internal/libfreenect2/depth_packet_stream_parser.h @@ -34,7 +34,6 @@ #include -#include #include #include @@ -70,7 +69,8 @@ class DepthPacketStreamParser : public DataCallback private: libfreenect2::BaseDepthPacketProcessor *processor_; - libfreenect2::DoubleBuffer buffer_; + size_t buffer_size_; + DepthPacket packet_; libfreenect2::Buffer work_buffer_; uint32_t processed_packets_; diff --git a/include/internal/libfreenect2/double_buffer.h b/include/internal/libfreenect2/double_buffer.h deleted file mode 100644 index 54f52ba25..000000000 --- a/include/internal/libfreenect2/double_buffer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of the OpenKinect Project. http://www.openkinect.org - * - * Copyright (c) 2014 individual OpenKinect contributors. See the CONTRIB file - * for details. - * - * This code is licensed to you under the terms of the Apache License, version - * 2.0, or, at your option, the terms of the GNU General Public License, - * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, - * or the following URLs: - * http://www.apache.org/licenses/LICENSE-2.0 - * http://www.gnu.org/licenses/gpl-2.0.txt - * - * If you redistribute this file in source form, modified or unmodified, you - * may: - * 1) Leave this header intact and distribute it under the same terms, - * accompanying it with the APACHE20 and GPL20 files, or - * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or - * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file - * In all cases you must keep the copyright notice intact and include a copy - * of the CONTRIB file. - * - * Binary distributions must follow the binary distribution requirements of - * either License. - */ - -/** @file double_buffer.h Double buffer implementation. */ - -#ifndef DOUBLE_BUFFER_H_ -#define DOUBLE_BUFFER_H_ - -#include -#include - -namespace libfreenect2 -{ - -/** Data of a single buffer. */ -struct Buffer -{ -public: - size_t capacity; ///< Capacity of the buffer. - size_t length; ///< Used length of the buffer. - unsigned char* data; ///< Start address of the buffer. -}; - -/** Double bufffer class. */ -class DoubleBuffer -{ -public: - DoubleBuffer(); - virtual ~DoubleBuffer(); - - void allocate(size_t buffer_size); - - void swap(); - - Buffer& front(); - - Buffer& back(); -private: - Buffer buffer_[2]; // Both data buffers. - unsigned char front_buffer_index_; ///< Index of the front buffer. - - unsigned char* buffer_data_; ///< Memory holding both buffers. -}; - -} /* namespace libfreenect2 */ -#endif /* DOUBLE_BUFFER_H_ */ diff --git a/include/internal/libfreenect2/packet_processor.h b/include/internal/libfreenect2/packet_processor.h index 05165879b..5ef0c2a0d 100644 --- a/include/internal/libfreenect2/packet_processor.h +++ b/include/internal/libfreenect2/packet_processor.h @@ -29,6 +29,8 @@ #ifndef PACKET_PROCESSOR_H_ #define PACKET_PROCESSOR_H_ +#include "libfreenect2/allocator.h" + namespace libfreenect2 { @@ -48,11 +50,34 @@ class PacketProcessor */ virtual bool ready() { return true; } + virtual bool good() { return true; } + /** * A new packet has arrived, process it. * @param packet Packet to process. */ virtual void process(const PacketT &packet) = 0; + + virtual void allocateBuffer(PacketT &p, size_t size) + { + Allocator *a = getAllocator(); + if (a) + p.memory = a->allocate(size); + } + + virtual void releaseBuffer(PacketT &p) + { + Allocator *a = getAllocator(); + if (a) + a->free(p.memory); + p.memory = NULL; + } + +protected: + virtual Allocator *getAllocator() { return &default_allocator_; } + +private: + PoolAllocator default_allocator_; }; /** diff --git a/include/internal/libfreenect2/rgb_packet_processor.h b/include/internal/libfreenect2/rgb_packet_processor.h index 534fc900a..411a54c54 100644 --- a/include/internal/libfreenect2/rgb_packet_processor.h +++ b/include/internal/libfreenect2/rgb_packet_processor.h @@ -51,6 +51,7 @@ struct RgbPacket float gain; float gamma; + Buffer *memory; }; typedef PacketProcessor BaseRgbPacketProcessor; @@ -73,7 +74,6 @@ class DumpRgbPacketProcessor : public RgbPacketProcessor public: DumpRgbPacketProcessor(); virtual ~DumpRgbPacketProcessor(); -protected: virtual void process(const libfreenect2::RgbPacket &packet); }; @@ -86,7 +86,6 @@ class TurboJpegRgbPacketProcessor : public RgbPacketProcessor public: TurboJpegRgbPacketProcessor(); virtual ~TurboJpegRgbPacketProcessor(); -protected: virtual void process(const libfreenect2::RgbPacket &packet); private: TurboJpegRgbPacketProcessorImpl *impl_; ///< Decoder implementation. @@ -101,12 +100,28 @@ class VTRgbPacketProcessor : public RgbPacketProcessor public: VTRgbPacketProcessor(); virtual ~VTRgbPacketProcessor(); -protected: virtual void process(const libfreenect2::RgbPacket &packet); private: VTRgbPacketProcessorImpl *impl_; }; #endif +#ifdef LIBFREENECT2_WITH_VAAPI_SUPPORT +class VaapiRgbPacketProcessorImpl; + +class VaapiRgbPacketProcessor : public RgbPacketProcessor +{ +public: + VaapiRgbPacketProcessor(); + virtual ~VaapiRgbPacketProcessor(); + virtual bool good(); + virtual void process(const libfreenect2::RgbPacket &packet); +protected: + virtual Allocator *getAllocator(); +private: + VaapiRgbPacketProcessorImpl *impl_; +}; +#endif //LIBFREENECT2_WITH_VAAPI_SUPPORT + } /* namespace libfreenect2 */ #endif /* RGB_PACKET_PROCESSOR_H_ */ diff --git a/include/internal/libfreenect2/rgb_packet_stream_parser.h b/include/internal/libfreenect2/rgb_packet_stream_parser.h index be099eb34..2cc7558be 100644 --- a/include/internal/libfreenect2/rgb_packet_stream_parser.h +++ b/include/internal/libfreenect2/rgb_packet_stream_parser.h @@ -32,7 +32,6 @@ #include #include -#include #include #include @@ -51,7 +50,8 @@ class RgbPacketStreamParser : public DataCallback virtual void onDataReceived(unsigned char* buffer, size_t length); private: - libfreenect2::DoubleBuffer buffer_; ///< Buffers for storage. + size_t buffer_size_; + RgbPacket packet_; BaseRgbPacketProcessor *processor_; ///< Parser implementation. }; diff --git a/include/libfreenect2/config.h.in b/include/libfreenect2/config.h.in index 126af602c..f916800b0 100644 --- a/include/libfreenect2/config.h.in +++ b/include/libfreenect2/config.h.in @@ -46,6 +46,8 @@ #cmakedefine LIBFREENECT2_WITH_VT_SUPPORT +#cmakedefine LIBFREENECT2_WITH_VAAPI_SUPPORT + #cmakedefine LIBFREENECT2_WITH_TURBOJPEG_SUPPORT #cmakedefine LIBFREENECT2_THREADING_STDLIB diff --git a/src/allocator.cpp b/src/allocator.cpp new file mode 100644 index 000000000..cbc1933ca --- /dev/null +++ b/src/allocator.cpp @@ -0,0 +1,116 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2014 individual OpenKinect contributors. See the CONTRIB file + * for details. + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +/** @file packet_processor.h Packet processor definitions. */ + +#include "libfreenect2/allocator.h" +#include "libfreenect2/threading.h" + +namespace libfreenect2 +{ +class NewAllocator: public Allocator +{ +public: + virtual Buffer *allocate(size_t size) + { + Buffer *b = new Buffer; + b->data = new unsigned char[size]; + b->length = 0; + b->capacity = size; + return b; + } + + virtual void free(Buffer *b) + { + if (b == NULL) + return; + delete[] b->data; + delete b; + } +}; + +class PoolAllocatorImpl +{ +private: + Allocator *allocator; + Buffer *buffers[2]; + mutex locks[2]; + int next; +public: + PoolAllocatorImpl(Allocator *a): allocator(a), buffers(), next(0) {} + + Buffer *allocate(size_t size) + { + locks[next].lock(); + if (buffers[next] == NULL) + buffers[next] = allocator->allocate(size); + buffers[next]->length = 0; + Buffer *b = buffers[next]; + next = !next; + return b; + } + + void free(Buffer *b) + { + if (b == buffers[0]) + locks[0].unlock(); + else if (b == buffers[1]) + locks[1].unlock(); + } + + ~PoolAllocatorImpl() + { + allocator->free(buffers[0]); + allocator->free(buffers[1]); + delete allocator; + } +}; + +PoolAllocator::PoolAllocator(): + impl_(new PoolAllocatorImpl(new NewAllocator)) +{ +} + +PoolAllocator::PoolAllocator(Allocator *a): + impl_(new PoolAllocatorImpl(a)) +{ +} + +PoolAllocator::~PoolAllocator() +{ + delete impl_; +} + +Buffer *PoolAllocator::allocate(size_t size) +{ + return impl_->allocate(size); +} + +void PoolAllocator::free(Buffer *b) +{ + impl_->free(b); +} +} // namespace libfreenect2 diff --git a/src/depth_packet_stream_parser.cpp b/src/depth_packet_stream_parser.cpp index 273d21abf..23bdd3150 100644 --- a/src/depth_packet_stream_parser.cpp +++ b/src/depth_packet_stream_parser.cpp @@ -40,10 +40,9 @@ DepthPacketStreamParser::DepthPacketStreamParser() : current_subsequence_(0) { size_t single_image = 512*424*11/8; + buffer_size_ = 10 * single_image; - buffer_.allocate((single_image) * 10); - buffer_.front().length = buffer_.front().capacity; - buffer_.back().length = buffer_.back().capacity; + processor_->allocateBuffer(packet_, buffer_size_); work_buffer_.data = new unsigned char[single_image]; work_buffer_.capacity = single_image; @@ -52,16 +51,22 @@ DepthPacketStreamParser::DepthPacketStreamParser() : DepthPacketStreamParser::~DepthPacketStreamParser() { - delete[] work_buffer_.data; } void DepthPacketStreamParser::setPacketProcessor(libfreenect2::BaseDepthPacketProcessor *processor) { + processor_->releaseBuffer(packet_); processor_ = (processor != 0) ? processor : noopProcessor(); + processor_->allocateBuffer(packet_, buffer_size_); } void DepthPacketStreamParser::onDataReceived(unsigned char* buffer, size_t in_length) { + if (packet_.memory == NULL || packet_.memory->data == NULL) + { + LOG_ERROR << "Packet buffer is NULL"; + return; + } Buffer &wb = work_buffer_; if(in_length == 0) @@ -105,15 +110,14 @@ void DepthPacketStreamParser::onDataReceived(unsigned char* buffer, size_t in_le { if(processor_->ready()) { - buffer_.swap(); - - DepthPacket packet; + DepthPacket &packet = packet_; packet.sequence = current_sequence_; packet.timestamp = footer->timestamp; - packet.buffer = buffer_.back().data; - packet.buffer_length = buffer_.back().length; + packet.buffer = packet_.memory->data; + packet.buffer_length = packet_.memory->capacity; processor_->process(packet); + processor_->allocateBuffer(packet_, buffer_size_); processed_packets_++; if (processed_packets_ == 0) @@ -140,12 +144,12 @@ void DepthPacketStreamParser::onDataReceived(unsigned char* buffer, size_t in_le current_subsequence_ = 0; } - Buffer &fb = buffer_.front(); + Buffer &fb = *packet_.memory; // set the bit corresponding to the subsequence number to 1 current_subsequence_ |= 1 << footer->subsequence; - if(footer->subsequence * footer->length > fb.length) + if(footer->subsequence * footer->length > fb.capacity) { LOG_DEBUG << "front buffer too short! subsequence number is " << footer->subsequence; } diff --git a/src/double_buffer.cpp b/src/double_buffer.cpp deleted file mode 100644 index c28808ed8..000000000 --- a/src/double_buffer.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of the OpenKinect Project. http://www.openkinect.org - * - * Copyright (c) 2014 individual OpenKinect contributors. See the CONTRIB file - * for details. - * - * This code is licensed to you under the terms of the Apache License, version - * 2.0, or, at your option, the terms of the GNU General Public License, - * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, - * or the following URLs: - * http://www.apache.org/licenses/LICENSE-2.0 - * http://www.gnu.org/licenses/gpl-2.0.txt - * - * If you redistribute this file in source form, modified or unmodified, you - * may: - * 1) Leave this header intact and distribute it under the same terms, - * accompanying it with the APACHE20 and GPL20 files, or - * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or - * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file - * In all cases you must keep the copyright notice intact and include a copy - * of the CONTRIB file. - * - * Binary distributions must follow the binary distribution requirements of - * either License. - */ - -/** @file double_buffer.cpp Double buffer implementation. */ - -#include - -namespace libfreenect2 -{ - -DoubleBuffer::DoubleBuffer() : - front_buffer_index_(0), - buffer_data_(0) -{ -} - -DoubleBuffer::~DoubleBuffer() -{ - if(buffer_data_ != 0) - { - buffer_[0].data = 0; - buffer_[1].data = 0; - delete[] buffer_data_; - } -} - -/** - * Allocate double buffering of capacity \a buffer_size. - * @param buffer_size Capacity of both buffers. - */ -void DoubleBuffer::allocate(size_t buffer_size) -{ - size_t total_buffer_size = 2 * buffer_size; - buffer_data_ = new unsigned char[total_buffer_size]; - - buffer_[0].capacity = buffer_size; - buffer_[0].length = 0; - buffer_[0].data = buffer_data_; - - buffer_[1].capacity = buffer_size; - buffer_[1].length = 0; - buffer_[1].data = buffer_data_ + buffer_size; -} - -/** Swap back and front buffer. */ -void DoubleBuffer::swap() -{ - front_buffer_index_ = (front_buffer_index_ + 1) & 1; -} - -/** - * Get front buffer. - * @return The front buffer. - */ -Buffer& DoubleBuffer::front() -{ - return buffer_[front_buffer_index_ & 1]; -} - -/** - * Get back buffer. - * @return The back buffer. - */ -Buffer& DoubleBuffer::back() -{ - return buffer_[(front_buffer_index_ + 1) & 1]; -} - -} /* namespace libfreenect2 */ diff --git a/src/packet_pipeline.cpp b/src/packet_pipeline.cpp index de5e88839..ac5c3ae35 100644 --- a/src/packet_pipeline.cpp +++ b/src/packet_pipeline.cpp @@ -40,6 +40,13 @@ static RgbPacketProcessor *getDefaultRgbPacketProcessor() { #if defined(LIBFREENECT2_WITH_VT_SUPPORT) return new VTRgbPacketProcessor(); +#elif defined(LIBFREENECT2_WITH_VAAPI_SUPPORT) + RgbPacketProcessor *vaapi = new VaapiRgbPacketProcessor(); + if (vaapi->good()) + return vaapi; + else + delete vaapi; + return new TurboJpegRgbPacketProcessor(); #elif defined(LIBFREENECT2_WITH_TURBOJPEG_SUPPORT) return new TurboJpegRgbPacketProcessor(); #else diff --git a/src/rgb_packet_stream_parser.cpp b/src/rgb_packet_stream_parser.cpp index bfd5eea66..1bf6e63f6 100644 --- a/src/rgb_packet_stream_parser.cpp +++ b/src/rgb_packet_stream_parser.cpp @@ -62,9 +62,10 @@ LIBFREENECT2_PACK(struct RgbPacketFooter { }); RgbPacketStreamParser::RgbPacketStreamParser() : + buffer_size_(2*1024*1024), processor_(noopProcessor()) { - buffer_.allocate(1920*1080*3+sizeof(RgbPacket)); + processor_->allocateBuffer(packet_, buffer_size_); } RgbPacketStreamParser::~RgbPacketStreamParser() @@ -73,12 +74,19 @@ RgbPacketStreamParser::~RgbPacketStreamParser() void RgbPacketStreamParser::setPacketProcessor(BaseRgbPacketProcessor *processor) { + processor_->releaseBuffer(packet_); processor_ = (processor != 0) ? processor : noopProcessor(); + processor_->allocateBuffer(packet_, buffer_size_); } void RgbPacketStreamParser::onDataReceived(unsigned char* buffer, size_t length) { - Buffer &fb = buffer_.front(); + if (packet_.memory == NULL || packet_.memory->data == NULL) + { + LOG_ERROR << "Packet buffer is NULL"; + return; + } + Buffer &fb = *packet_.memory; // package containing data if(length > 0) @@ -142,11 +150,7 @@ void RgbPacketStreamParser::onDataReceived(unsigned char* buffer, size_t length) // can the processor handle the next image? if(processor_->ready()) { - buffer_.swap(); - Buffer &bb = buffer_.back(); - - RawRgbPacket *raw_packet = reinterpret_cast(bb.data); - RgbPacket rgb_packet; + RgbPacket &rgb_packet = packet_; rgb_packet.sequence = raw_packet->sequence; rgb_packet.timestamp = footer->timestamp; rgb_packet.exposure = footer->exposure; @@ -157,6 +161,8 @@ void RgbPacketStreamParser::onDataReceived(unsigned char* buffer, size_t length) // call the processor processor_->process(rgb_packet); + //allocatePacket() should never return NULL when processor is ready() + processor_->allocateBuffer(packet_, buffer_size_); } else { @@ -164,7 +170,7 @@ void RgbPacketStreamParser::onDataReceived(unsigned char* buffer, size_t length) } // reset front buffer - buffer_.front().length = 0; + packet_.memory->length = 0; } } } diff --git a/src/vaapi_rgb_packet_processor.cpp b/src/vaapi_rgb_packet_processor.cpp new file mode 100644 index 000000000..63c027972 --- /dev/null +++ b/src/vaapi_rgb_packet_processor.cpp @@ -0,0 +1,453 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2014 individual OpenKinect contributors. See the CONTRIB file + * for details. + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +#include + +#include +#include //jpeglib.h does not include stdio.h +#include +#include +#include +#include +#include +#include "libfreenect2/logging.h" +#include "libfreenect2/allocator.h" + +#define CHECK_COND(cond) do { if (!(cond)) { LOG_ERROR << #cond " failed"; return false; } } while(0) +#define CHECK_VA(expr) do { VAStatus err = (expr); if (err != VA_STATUS_SUCCESS) { LOG_ERROR << #expr ": " << vaErrorStr(err); return false; } } while(0) +#define CALL_VA(expr) do { VAStatus err = (expr); if (err != VA_STATUS_SUCCESS) { LOG_ERROR << #expr ": " << vaErrorStr(err); } } while(0) + +namespace libfreenect2 +{ + +class VaapiFrame: public Frame +{ +public: + VADisplay display; + VAImage image; + + VaapiFrame(VADisplay display, size_t width, size_t height, size_t bytes_per_pixel): + Frame(width, height, bytes_per_pixel, (unsigned char*)-1), + display(display) + { + data = NULL; + + /* Create image */ + VAImageFormat format = {0}; + format.fourcc = VA_FOURCC_BGRX; + format.byte_order = VA_LSB_FIRST; + format.bits_per_pixel = bytes_per_pixel*8; + format.depth = 8; + + CALL_VA(vaCreateImage(display, &format, width, height, &image)); + } + + bool draw(VASurfaceID surface) + { + if (data != NULL) { + data = NULL; + CHECK_VA(vaUnmapBuffer(display, image.buf)); + } + CHECK_VA(vaGetImage(display, surface, 0, 0, width, height, image.image_id)); + CHECK_VA(vaMapBuffer(display, image.buf, (void**)&data)); + return true; + } + + ~VaapiFrame() + { + if (data != NULL) { + CALL_VA(vaUnmapBuffer(display, image.buf)); + data = NULL; + } + CALL_VA(vaDestroyImage(display, image.image_id)); + } +}; + +class VaapiBuffer: public Buffer +{ +public: + VABufferID id; + + VaapiBuffer(): Buffer(), id(VA_INVALID_ID) {} +}; + +class VaapiAllocator: public Allocator +{ +private: + VADisplay display; + VAContextID context; + + bool allocate_va(VaapiBuffer *b, size_t size) + { + CHECK_VA(vaCreateBuffer(display, context, VASliceDataBufferType, size, 1, NULL, &b->id)); + CHECK_VA(vaMapBuffer(display, b->id, (void**)&b->data)); + b->capacity = size; + return true; + } + +public: + VaapiAllocator(VADisplay display, VAContextID context): + display(display), context(context) {} + + virtual Buffer *allocate(size_t size) + { + VaapiBuffer *vb = new VaapiBuffer(); + if (!allocate_va(vb, size)) + vb->data = NULL; + return vb; + } + + virtual void free(Buffer *b) + { + if (b == NULL) + return; + VaapiBuffer *vb = static_cast(b); + if (vb->data) { + CALL_VA(vaUnmapBuffer(display, vb->id)); + CALL_VA(vaDestroyBuffer(display, vb->id)); + } + delete vb; + } +}; + +class VaapiRgbPacketProcessorImpl: public WithPerfLogging +{ +public: + int drm_fd; + VADisplay display; + VAConfigID config; + VASurfaceID surface; + VAContextID context; + + VABufferID pic_param_buf; + VABufferID iq_buf; + VABufferID huff_buf; + VABufferID slice_param_buf; + + bool jpeg_first_packet; + size_t jpeg_header_size; + + struct jpeg_decompress_struct dinfo; + struct jpeg_error_mgr jerr; + + bool good; + + static const int WIDTH = 1920; + static const int HEIGHT = 1080; + + VaapiFrame *frame; + + Allocator *allocator_; + + VaapiRgbPacketProcessorImpl(): + frame(NULL), + allocator_(NULL) + { + dinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&dinfo); + + good = initializeVaapi(); + if (!good) + return; + + newFrame(); + + allocator_ = new PoolAllocator(new VaapiAllocator(display, context)); + + jpeg_first_packet = true; + } + + ~VaapiRgbPacketProcessorImpl() + { + delete frame; + delete allocator_; + if (good && !jpeg_first_packet) { + CALL_VA(vaDestroyBuffer(display, pic_param_buf)); + CALL_VA(vaDestroyBuffer(display, iq_buf)); + CALL_VA(vaDestroyBuffer(display, huff_buf)); + CALL_VA(vaDestroyBuffer(display, slice_param_buf)); + } + if (good) { + CALL_VA(vaDestroyContext(display, context)); + CALL_VA(vaDestroySurfaces(display, &surface, 1)); + CALL_VA(vaDestroyConfig(display, config)); + CALL_VA(vaTerminate(display)); + } + if (drm_fd >= 0) + close(drm_fd); + jpeg_destroy_decompress(&dinfo); + } + + void newFrame() + { + frame = new VaapiFrame(display, WIDTH, HEIGHT, 4); + } + + bool initializeVaapi() + { + /* Open display */ + static const char *drm_devices[] = { + "/dev/dri/renderD128", + "/dev/dri/card0", + NULL, + }; + for (int i = 0; drm_devices[i]; i++) { + drm_fd = open(drm_devices[i], O_RDWR); + if (drm_fd < 0) + continue; + display = vaGetDisplayDRM(drm_fd); + if (vaDisplayIsValid(display)) + break; + close(drm_fd); + drm_fd = -1; + display = NULL; + } + CHECK_COND(vaDisplayIsValid(display)); + + /* Initialize and create config */ + int major_ver, minor_ver; + CHECK_VA(vaInitialize(display, &major_ver, &minor_ver)); + + LOG_INFO << "driver: " << vaQueryVendorString(display); + + int max_entrypoints = vaMaxNumEntrypoints(display); + CHECK_COND(max_entrypoints >= 1); + + VAEntrypoint entrypoints[max_entrypoints]; + int num_entrypoints; + CHECK_VA(vaQueryConfigEntrypoints(display, VAProfileJPEGBaseline, entrypoints, &num_entrypoints)); + CHECK_COND(num_entrypoints >= 1 && num_entrypoints <= max_entrypoints); + + int vld_entrypoint; + for (vld_entrypoint = 0; vld_entrypoint < num_entrypoints; vld_entrypoint++) { + if (entrypoints[vld_entrypoint] == VAEntrypointVLD) + break; + } + CHECK_COND(vld_entrypoint < num_entrypoints); + + VAConfigAttrib attr; + attr.type = VAConfigAttribRTFormat; + CHECK_VA(vaGetConfigAttributes(display, VAProfileJPEGBaseline, VAEntrypointVLD, &attr, 1)); + unsigned int rtformat = VA_RT_FORMAT_YUV444; + if ((attr.value & rtformat) == 0) { + LOG_WARNING << "YUV444 not supported by libva, chroma will be halved"; + rtformat = VA_RT_FORMAT_YUV420; + } + CHECK_COND((attr.value & rtformat) != 0); + + CHECK_VA(vaCreateConfig(display, VAProfileJPEGBaseline, VAEntrypointVLD, &attr, 1, &config)); + + /* Create surface and context */ + CHECK_VA(vaCreateSurfaces(display, rtformat, WIDTH, HEIGHT, &surface, 1, NULL, 0)); + + CHECK_VA(vaCreateContext(display, config, WIDTH, HEIGHT, 0, &surface, 1, &context)); + + return true; + } + + VABufferID createBuffer(VABufferType type, unsigned int size, void *data) + { + VABufferID buffer = VA_INVALID_ID; + CALL_VA(vaCreateBuffer(display, context, type, size, 1, data, &buffer)); + if (buffer == VA_INVALID_ID) + LOG_ERROR << "failed to create valid buffer"; + return buffer; + } + + bool createParameters(struct jpeg_decompress_struct &dinfo, const unsigned char *vb_start) + { + /* Picture Parameter */ + VAPictureParameterBufferJPEGBaseline pic = {0}; + pic.picture_width = dinfo.image_width; + pic.picture_height = dinfo.image_height; + for (int i = 0; i< dinfo.num_components; i++) { + pic.components[i].component_id = dinfo.comp_info[i].component_id; + pic.components[i].h_sampling_factor = dinfo.comp_info[i].h_samp_factor; + pic.components[i].v_sampling_factor = dinfo.comp_info[i].v_samp_factor; + pic.components[i].quantiser_table_selector = dinfo.comp_info[i].quant_tbl_no; + } + pic.num_components = dinfo.num_components; + pic_param_buf = createBuffer(VAPictureParameterBufferType, sizeof(pic), &pic); + + /* IQ Matrix */ + VAIQMatrixBufferJPEGBaseline iq = {0}; + for (int i = 0; i < NUM_QUANT_TBLS; i++) { + if (!dinfo.quant_tbl_ptrs[i]) + continue; + iq.load_quantiser_table[i] = 1; + /* Assuming dinfo.data_precision == 8 */ + const int natural_order[DCTSIZE2] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + }; + + for (int j = 0; j < DCTSIZE2; j++) + iq.quantiser_table[i][j] = dinfo.quant_tbl_ptrs[i]->quantval[natural_order[j]]; + } + iq_buf = createBuffer(VAIQMatrixBufferType, sizeof(iq), &iq); + + /* Huffman Table */ + VAHuffmanTableBufferJPEGBaseline huff = {0}; + const int num_huffman_tables = 2; + for (int i = 0; i < num_huffman_tables; i++) { + if (!dinfo.dc_huff_tbl_ptrs[i] || !dinfo.ac_huff_tbl_ptrs[i]) + continue; + huff.load_huffman_table[i] = 1; + memcpy(huff.huffman_table[i].num_dc_codes, &dinfo.dc_huff_tbl_ptrs[i]->bits[1], + sizeof(huff.huffman_table[i].num_dc_codes)); + memcpy(huff.huffman_table[i].dc_values, dinfo.dc_huff_tbl_ptrs[i]->huffval, + sizeof(huff.huffman_table[i].dc_values)); + memcpy(huff.huffman_table[i].num_ac_codes, &dinfo.ac_huff_tbl_ptrs[i]->bits[1], + sizeof(huff.huffman_table[i].num_ac_codes)); + memcpy(huff.huffman_table[i].ac_values, dinfo.ac_huff_tbl_ptrs[i]->huffval, + sizeof(huff.huffman_table[i].ac_values)); + } + huff_buf = createBuffer(VAHuffmanTableBufferType, sizeof(huff), &huff); + + /* Slice Parameter */ + VASliceParameterBufferJPEGBaseline *pslice; + slice_param_buf = createBuffer(VASliceParameterBufferType, sizeof(*pslice), NULL); + CHECK_VA(vaMapBuffer(display, slice_param_buf, (void**)&pslice)); + VASliceParameterBufferJPEGBaseline &slice = *pslice; + + slice.slice_data_offset = dinfo.src->next_input_byte - vb_start; + slice.slice_data_flag = VA_SLICE_DATA_FLAG_ALL; + for (int i = 0; i < dinfo.comps_in_scan; i++) { + slice.components[i].component_selector = dinfo.cur_comp_info[i]->component_id; + slice.components[i].dc_table_selector = dinfo.cur_comp_info[i]->dc_tbl_no; + slice.components[i].ac_table_selector = dinfo.cur_comp_info[i]->ac_tbl_no; + } + slice.num_components = dinfo.comps_in_scan; + slice.restart_interval = dinfo.restart_interval; + unsigned int mcu_h_size = dinfo.max_h_samp_factor * DCTSIZE; + unsigned int mcu_v_size = dinfo.max_v_samp_factor * DCTSIZE; + unsigned int mcus_per_row = (WIDTH + mcu_h_size - 1) / mcu_h_size; + unsigned int mcu_rows_in_scan = (HEIGHT + mcu_v_size - 1) / mcu_v_size; + slice.num_mcus = mcus_per_row * mcu_rows_in_scan; + + CHECK_VA(vaUnmapBuffer(display, slice_param_buf)); + return true; + } + + bool decompress(unsigned char *buf, size_t len, VaapiBuffer *vb) + { + if (jpeg_first_packet) { + jpeg_mem_src(&dinfo, buf, len); + int header_status = jpeg_read_header(&dinfo, true); + CHECK_COND(header_status == JPEG_HEADER_OK); + CHECK_COND(dinfo.image_width == WIDTH && dinfo.image_height == HEIGHT); + + jpeg_first_packet = false; + if (!createParameters(dinfo, vb->data)) + return false; + + jpeg_header_size = len - dinfo.src->bytes_in_buffer; + jpeg_abort_decompress(&dinfo); + } + /* Grab the packet buffer for VAAPI backend */ + CHECK_VA(vaUnmapBuffer(display, vb->id)); + + /* The only parameter that changes after the first packet */ + VASliceParameterBufferJPEGBaseline *slice; + CHECK_VA(vaMapBuffer(display, slice_param_buf, (void**)&slice)); + slice->slice_data_size = len - jpeg_header_size; + CHECK_VA(vaUnmapBuffer(display, slice_param_buf)); + + /* Commit buffers */ + CHECK_VA(vaBeginPicture(display, context, surface)); + VABufferID va_bufs[5] = {pic_param_buf, iq_buf, huff_buf, slice_param_buf, vb->id}; + CHECK_VA(vaRenderPicture(display, context, va_bufs, 5)); + CHECK_VA(vaEndPicture(display, context)); + + /* Sync surface */ + CHECK_VA(vaSyncSurface(display, surface)); + + if (!frame->draw(surface)) + return false; + + CHECK_VA(vaMapBuffer(display, vb->id, (void**)&vb->data)); + + return true; + } +}; + +VaapiRgbPacketProcessor::VaapiRgbPacketProcessor() : + impl_(new VaapiRgbPacketProcessorImpl()) +{ +} + +VaapiRgbPacketProcessor::~VaapiRgbPacketProcessor() +{ + delete impl_; +} + +bool VaapiRgbPacketProcessor::good() +{ + return impl_->good; +} + +void VaapiRgbPacketProcessor::process(const RgbPacket &packet) +{ + if (listener_ == 0) + return; + + if (!impl_->good) { + LOG_ERROR << "libva in error state"; + return; + } + + impl_->startTiming(); + + impl_->frame->timestamp = packet.timestamp; + impl_->frame->sequence = packet.sequence; + impl_->frame->exposure = packet.exposure; + impl_->frame->gain = packet.gain; + impl_->frame->gamma = packet.gamma; + + unsigned char *buf = packet.jpeg_buffer; + size_t len = packet.jpeg_buffer_length; + VaapiBuffer *vb = static_cast(packet.memory); + impl_->good = impl_->decompress(buf, len, vb); + + impl_->stopTiming(LOG_INFO); + + if (impl_->good) { + if (listener_->onNewFrame(Frame::Color, impl_->frame)) + impl_->newFrame(); + } +} + +Allocator *VaapiRgbPacketProcessor::getAllocator() +{ + return impl_->allocator_; +} +} /* namespace libfreenect2 */