Skip to content

Commit 20185c3

Browse files
committed
New VideoToolbox rgb packet processor
Mac OS X >= 10.8 has hardware accelerated jpeg decoding (a bit hidden)
1 parent b8aaef1 commit 20185c3

File tree

7 files changed

+266
-19
lines changed

7 files changed

+266
-19
lines changed

CMakeLists.txt

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
5353
# dependencies
5454
FIND_PACKAGE(PkgConfig) # try find PKGConfig as it will be used if found
5555
FIND_PACKAGE(LibUSB REQUIRED)
56-
FIND_PACKAGE(TurboJPEG REQUIRED) #does not provide a package-config file
5756

5857
# Add includes
5958
INCLUDE_DIRECTORIES(
@@ -62,7 +61,6 @@ INCLUDE_DIRECTORIES(
6261
${PROJECT_BINARY_DIR} # for generated headers
6362
${LIBFREENECT2_THREADING_INCLUDE_DIR}
6463
${LibUSB_INCLUDE_DIRS}
65-
${TurboJPEG_INCLUDE_DIRS}
6664
)
6765

6866
LINK_DIRECTORIES(${LibUSB_LIBRARY_DIRS})
@@ -105,7 +103,6 @@ SET(SOURCES
105103
src/packet_pipeline.cpp
106104
src/rgb_packet_stream_parser.cpp
107105
src/rgb_packet_processor.cpp
108-
src/turbo_jpeg_rgb_packet_processor.cpp
109106
src/depth_packet_stream_parser.cpp
110107
src/depth_packet_processor.cpp
111108
src/cpu_depth_packet_processor.cpp
@@ -122,10 +119,52 @@ SET(SOURCES
122119

123120
SET(LIBRARIES
124121
${LibUSB_LIBRARIES}
125-
${TurboJPEG_LIBRARIES}
126122
${LIBFREENECT2_THREADING_LIBRARIES}
127123
)
128124

125+
IF(APPLE)
126+
FIND_LIBRARY(VIDEOTOOLBOX_LIBRARY VideoToolbox)
127+
128+
IF(VIDEOTOOLBOX_LIBRARY)
129+
SET(LIBFREENECT2_WITH_VT_SUPPORT 1)
130+
131+
FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED)
132+
FIND_LIBRARY(COREMEDIA_LIBRARY CoreMedia REQUIRED)
133+
FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo REQUIRED)
134+
135+
LIST(APPEND SOURCES
136+
src/vt_rgb_packet_processor.cpp
137+
)
138+
139+
LIST(APPEND LIBRARIES
140+
${VIDEOTOOLBOX_LIBRARY}
141+
${COREFOUNDATION_LIBRARY}
142+
${COREMEDIA_LIBRARY}
143+
${COREVIDEO_LIBRARY}
144+
)
145+
ENDIF(VIDEOTOOLBOX_LIBRARY)
146+
ENDIF(APPLE)
147+
148+
IF(LIBFREENECT2_WITH_VT_SUPPORT)
149+
FIND_PACKAGE(TurboJPEG)
150+
ELSE()
151+
FIND_PACKAGE(TurboJPEG REQUIRED)
152+
ENDIF()
153+
154+
IF(TurboJPEG_FOUND)
155+
SET(LIBFREENECT2_WITH_TURBOJPEG_SUPPORT 1)
156+
157+
INCLUDE_DIRECTORIES(${TurboJPEG_INCLUDE_DIRS})
158+
159+
LIST(APPEND SOURCES
160+
src/turbo_jpeg_rgb_packet_processor.cpp
161+
)
162+
163+
LIST(APPEND LIBRARIES
164+
${TurboJPEG_LIBRARIES}
165+
)
166+
ENDIF()
167+
129168
IF(ENABLE_OPENGL)
130169
FIND_PACKAGE(GLFW3)
131170
FIND_PACKAGE(OpenGL)

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,20 +149,16 @@ Use your favorite package managers (brew, ports, etc.)
149149

150150
1. ``cd`` into a directory where you want to keep libfreenect2 stuff in
151151
1. Make sure these build tools are available: wget, git, cmake, pkg-config, automake, autoconf, libtool. Xcode may provide some of them. Install the rest via package managers.
152-
1. Install dependencies: TurboJPEG, GLFW.
152+
1. Install dependencies: GLFW.
153153

154154
```
155155
brew update
156-
brew tap homebrew/science
157-
brew install jpeg-turbo
158156
brew tap homebrew/versions
159157
brew install glfw3
160158
```
161159

162160
Do not install libusb via package managers for libfreenect2. libfreenect2 includes an unreleased local version of libusb with USB3 specific patches. libfreenect2's libusb should still work fine in presence of a global version libusb.
163161

164-
It is not recommended to build TurboJPEG from source, which produces corrupted results on Mac OSX according to reports. Install TurboJPEG binary only from package managers.
165-
166162
1. Download the libfreenect2 repository
167163

168164
```

include/libfreenect2/config.h.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040

4141
#cmakedefine LIBFREENECT2_WITH_OPENCL_SUPPORT
4242

43+
#cmakedefine LIBFREENECT2_WITH_VT_SUPPORT
44+
45+
#cmakedefine LIBFREENECT2_WITH_TURBOJPEG_SUPPORT
46+
4347
#cmakedefine LIBFREENECT2_THREADING_STDLIB
4448

4549
#cmakedefine LIBFREENECT2_THREADING_TINYTHREAD

include/libfreenect2/frame_listener.hpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,30 @@ class LIBFREENECT2_API Frame
5555
size_t bytes_per_pixel; ///< Number of bytes in a pixel.
5656
unsigned char* data; ///< Data of the frame (aligned).
5757

58-
Frame(size_t width, size_t height, size_t bytes_per_pixel) :
58+
Frame(size_t width, size_t height, size_t bytes_per_pixel, unsigned char* _data = NULL) :
5959
width(width),
6060
height(height),
61-
bytes_per_pixel(bytes_per_pixel)
61+
bytes_per_pixel(bytes_per_pixel),
62+
rawdata(NULL),
63+
data(_data)
6264
{
63-
const size_t alignment = 64;
64-
size_t space = width * height * bytes_per_pixel + alignment;
65-
rawdata = new unsigned char[space];
66-
uintptr_t ptr = reinterpret_cast<uintptr_t>(rawdata);
67-
uintptr_t aligned = (ptr - 1u + alignment) & -alignment;
68-
data = reinterpret_cast<unsigned char *>(aligned);
65+
if (data == NULL)
66+
{
67+
const size_t alignment = 64;
68+
size_t space = width * height * bytes_per_pixel + alignment;
69+
rawdata = new unsigned char[space];
70+
uintptr_t ptr = reinterpret_cast<uintptr_t>(rawdata);
71+
uintptr_t aligned = (ptr - 1u + alignment) & -alignment;
72+
data = reinterpret_cast<unsigned char *>(aligned);
73+
}
6974
}
7075

71-
~Frame()
76+
virtual ~Frame()
7277
{
73-
delete[] rawdata;
78+
if (rawdata)
79+
{
80+
delete[] rawdata;
81+
}
7482
}
7583

7684
protected:

include/libfreenect2/rgb_packet_processor.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class LIBFREENECT2_API DumpRgbPacketProcessor : public RgbPacketProcessor
7373
virtual void process(const libfreenect2::RgbPacket &packet);
7474
};
7575

76+
#ifdef LIBFREENECT2_WITH_TURBOJPEG_SUPPORT
7677
class TurboJpegRgbPacketProcessorImpl;
7778

7879
/** Processor to decode JPEG to image, using TurboJpeg. */
@@ -86,6 +87,22 @@ class LIBFREENECT2_API TurboJpegRgbPacketProcessor : public RgbPacketProcessor
8687
private:
8788
TurboJpegRgbPacketProcessorImpl *impl_; ///< Decoder implementation.
8889
};
90+
#endif
91+
92+
#ifdef LIBFREENECT2_WITH_VT_SUPPORT
93+
class VTRgbPacketProcessorImpl;
94+
95+
class LIBFREENECT2_API VTRgbPacketProcessor : public RgbPacketProcessor
96+
{
97+
public:
98+
VTRgbPacketProcessor();
99+
virtual ~VTRgbPacketProcessor();
100+
protected:
101+
virtual void process(const libfreenect2::RgbPacket &packet);
102+
private:
103+
VTRgbPacketProcessorImpl *impl_;
104+
};
105+
#endif
89106

90107
} /* namespace libfreenect2 */
91108
#endif /* RGB_PACKET_PROCESSOR_H_ */

src/packet_pipeline.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ void BasePacketPipeline::initialize()
4444
rgb_parser_ = new RgbPacketStreamParser();
4545
depth_parser_ = new DepthPacketStreamParser();
4646

47+
#ifdef LIBFREENECT2_WITH_VT_SUPPORT
48+
rgb_processor_ = new VTRgbPacketProcessor();
49+
#else
4750
rgb_processor_ = new TurboJpegRgbPacketProcessor();
51+
#endif
52+
4853
depth_processor_ = createDepthPacketProcessor();
4954

5055
async_rgb_processor_ = new AsyncPacketProcessor<RgbPacket>(rgb_processor_);

src/vt_rgb_packet_processor.cpp

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* This file is part of the OpenKinect Project. http://www.openkinect.org
3+
*
4+
* Copyright (c) 2014 individual OpenKinect contributors. See the CONTRIB file
5+
* for details.
6+
*
7+
* This code is licensed to you under the terms of the Apache License, version
8+
* 2.0, or, at your option, the terms of the GNU General Public License,
9+
* version 2.0. See the APACHE20 and GPL2 files for the text of the licenses,
10+
* or the following URLs:
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
* http://www.gnu.org/licenses/gpl-2.0.txt
13+
*
14+
* If you redistribute this file in source form, modified or unmodified, you
15+
* may:
16+
* 1) Leave this header intact and distribute it under the same terms,
17+
* accompanying it with the APACHE20 and GPL20 files, or
18+
* 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or
19+
* 3) Delete the GPL v2 clause and accompany it with the APACHE20 file
20+
* In all cases you must keep the copyright notice intact and include a copy
21+
* of the CONTRIB file.
22+
*
23+
* Binary distributions must follow the binary distribution requirements of
24+
* either License.
25+
*/
26+
27+
28+
#include <libfreenect2/rgb_packet_processor.h>
29+
#include <libfreenect2/logging.h>
30+
31+
#include <VideoToolbox/VideoToolbox.h>
32+
33+
namespace libfreenect2 {
34+
35+
class VTFrame: public Frame
36+
{
37+
public:
38+
VTFrame(size_t width, size_t height, size_t bytes_per_pixel, CVPixelBufferRef pixelBuffer) :
39+
Frame(width,
40+
height,
41+
bytes_per_pixel,
42+
reinterpret_cast<unsigned char *>(CVPixelBufferGetBaseAddress(lockPixelBuffer(pixelBuffer)))),
43+
pixelBuffer(pixelBuffer) {
44+
}
45+
46+
~VTFrame() {
47+
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
48+
CVPixelBufferRelease(pixelBuffer);
49+
}
50+
51+
protected:
52+
CVPixelBufferRef lockPixelBuffer(CVPixelBufferRef _pixelBuffer) {
53+
CVPixelBufferLockBaseAddress(_pixelBuffer, 0);
54+
55+
return _pixelBuffer;
56+
}
57+
58+
CVPixelBufferRef pixelBuffer;
59+
};
60+
61+
class VTRgbPacketProcessorImpl: public WithPerfLogging
62+
{
63+
public:
64+
CMFormatDescriptionRef format;
65+
VTDecompressionSessionRef decoder;
66+
67+
VTRgbPacketProcessorImpl() {
68+
int32_t width = 1920, height = 1080;
69+
70+
CMVideoFormatDescriptionCreate(NULL, kCMVideoCodecType_JPEG, width, height, nil, &format);
71+
72+
const void *decoderSpecificationKeys[] = {kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder};
73+
const void *decoderSpecificationValues[] = {kCFBooleanTrue};
74+
CFDictionaryRef decoderSpecification = CFDictionaryCreate(NULL,
75+
decoderSpecificationKeys,
76+
decoderSpecificationValues,
77+
1,
78+
&kCFTypeDictionaryKeyCallBacks,
79+
&kCFTypeDictionaryValueCallBacks);
80+
81+
int32_t pixelFormat = kCVPixelFormatType_32BGRA;
82+
const void *outputKeys[] = {kCVPixelBufferPixelFormatTypeKey, kCVPixelBufferWidthKey, kCVPixelBufferHeightKey};
83+
const void *outputValues[] =
84+
{CFNumberCreate(NULL, kCFNumberSInt32Type, &pixelFormat), CFNumberCreate(NULL, kCFNumberSInt32Type, &width),
85+
CFNumberCreate(NULL, kCFNumberSInt32Type, &height)};
86+
87+
CFDictionaryRef outputConfiguration = CFDictionaryCreate(NULL,
88+
outputKeys,
89+
outputValues,
90+
3,
91+
&kCFTypeDictionaryKeyCallBacks,
92+
&kCFTypeDictionaryValueCallBacks);
93+
94+
VTDecompressionOutputCallbackRecord callback = {&VTRgbPacketProcessorImpl::decodeFrame, NULL};
95+
96+
VTDecompressionSessionCreate(NULL, format, decoderSpecification, outputConfiguration, &callback, &decoder);
97+
98+
CFRelease(decoderSpecification);
99+
CFRelease(outputConfiguration);
100+
}
101+
102+
~VTRgbPacketProcessorImpl() {
103+
VTDecompressionSessionInvalidate(decoder);
104+
CFRelease(decoder);
105+
CFRelease(format);
106+
}
107+
108+
static void decodeFrame(void *decompressionOutputRefCon,
109+
void *sourceFrameRefCon,
110+
OSStatus status,
111+
VTDecodeInfoFlags infoFlags,
112+
CVImageBufferRef pixelBuffer,
113+
CMTime presentationTimeStamp,
114+
CMTime presentationDuration) {
115+
CVPixelBufferRef *outputPixelBuffer = (CVPixelBufferRef *) sourceFrameRefCon;
116+
*outputPixelBuffer = CVPixelBufferRetain(pixelBuffer);
117+
}
118+
};
119+
120+
VTRgbPacketProcessor::VTRgbPacketProcessor() :
121+
impl_(new VTRgbPacketProcessorImpl())
122+
{
123+
}
124+
125+
VTRgbPacketProcessor::~VTRgbPacketProcessor()
126+
{
127+
delete impl_;
128+
}
129+
130+
void VTRgbPacketProcessor::process(const RgbPacket &packet)
131+
{
132+
if (listener_ != 0) {
133+
impl_->startTiming();
134+
135+
CMBlockBufferRef blockBuffer;
136+
CMBlockBufferCreateWithMemoryBlock(
137+
NULL,
138+
packet.jpeg_buffer,
139+
packet.jpeg_buffer_length,
140+
kCFAllocatorNull,
141+
NULL,
142+
0,
143+
packet.jpeg_buffer_length,
144+
0,
145+
&blockBuffer
146+
);
147+
148+
CMSampleBufferRef sampleBuffer;
149+
CMSampleBufferCreateReady(
150+
NULL,
151+
blockBuffer,
152+
impl_->format,
153+
1,
154+
0,
155+
NULL,
156+
0,
157+
NULL,
158+
&sampleBuffer
159+
);
160+
161+
CVPixelBufferRef pixelBuffer = NULL;
162+
VTDecompressionSessionDecodeFrame(impl_->decoder, sampleBuffer, 0, &pixelBuffer, NULL);
163+
164+
Frame *frame = new VTFrame(1920, 1080, 4, pixelBuffer);
165+
166+
frame->timestamp = packet.timestamp;
167+
frame->sequence = packet.sequence;
168+
169+
listener_->onNewFrame(Frame::Color, frame);
170+
171+
CFRelease(sampleBuffer);
172+
CFRelease(blockBuffer);
173+
174+
impl_->stopTiming(LOG_INFO);
175+
}
176+
}
177+
178+
} /* namespace libfreenect2 */

0 commit comments

Comments
 (0)