Skip to content

Commit 294cf52

Browse files
committed
New VideoToolbox rgb packet processor
Mac OS X >= 10.8 has hardware accelerated jpeg decoding (a bit hidden)
1 parent 7691a03 commit 294cf52

File tree

7 files changed

+266
-19
lines changed

7 files changed

+266
-19
lines changed

README.md

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

145145
1. ``cd`` into a directory where you want to keep libfreenect2 stuff in
146146
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.
147-
1. Install dependencies: TurboJPEG, GLFW.
147+
1. Install dependencies: GLFW.
148148

149149
```
150150
brew update
151-
brew tap homebrew/science
152-
brew install jpeg-turbo
153151
brew tap homebrew/versions
154152
brew install glfw3
155153
```
156154

157155
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.
158156

159-
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.
160-
161157
1. Download the libfreenect2 repository
162158

163159
```

examples/protonect/CMakeLists.txt

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,12 @@ SET(LIBRARY_OUTPUT_PATH ${MY_DIR}/lib)
4747
# dependencies
4848
FIND_PACKAGE(PkgConfig) # try find PKGConfig as it will be used if found
4949
FIND_PACKAGE(LibUSB REQUIRED)
50-
FIND_PACKAGE(TurboJPEG REQUIRED) #does not provide a package-config file
5150

5251
# Add includes
5352
INCLUDE_DIRECTORIES(
5453
"${MY_DIR}/include"
5554
${LIBFREENECT2_THREADING_INCLUDE_DIR}
5655
${LibUSB_INCLUDE_DIRS}
57-
${TurboJPEG_INCLUDE_DIRS}
5856
)
5957

6058
LINK_DIRECTORIES(${LibUSB_LIBRARY_DIRS})
@@ -94,7 +92,6 @@ SET(SOURCES
9492
src/packet_pipeline.cpp
9593
src/rgb_packet_stream_parser.cpp
9694
src/rgb_packet_processor.cpp
97-
src/turbo_jpeg_rgb_packet_processor.cpp
9895
src/depth_packet_stream_parser.cpp
9996
src/depth_packet_processor.cpp
10097
src/cpu_depth_packet_processor.cpp
@@ -110,7 +107,6 @@ SET(SOURCES
110107

111108
SET(LIBRARIES
112109
${LibUSB_LIBRARIES}
113-
${TurboJPEG_LIBRARIES}
114110
${LIBFREENECT2_THREADING_LIBRARIES}
115111
)
116112

@@ -176,6 +172,49 @@ IF(ENABLE_OPENCL)
176172
ENDIF(OPENCL_FOUND)
177173
ENDIF(ENABLE_OPENCL)
178174

175+
IF(APPLE)
176+
FIND_LIBRARY(VIDEOTOOLBOX_LIBRARY VideoToolbox)
177+
178+
IF(VIDEOTOOLBOX_LIBRARY)
179+
SET(LIBFREENECT2_WITH_VT_SUPPORT 1)
180+
181+
FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED)
182+
FIND_LIBRARY(COREMEDIA_LIBRARY CoreMedia REQUIRED)
183+
FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo REQUIRED)
184+
185+
LIST(APPEND SOURCES
186+
src/vt_rgb_packet_processor.cpp
187+
)
188+
189+
LIST(APPEND LIBRARIES
190+
${VIDEOTOOLBOX_LIBRARY}
191+
${COREFOUNDATION_LIBRARY}
192+
${COREMEDIA_LIBRARY}
193+
${COREVIDEO_LIBRARY}
194+
)
195+
ENDIF(VIDEOTOOLBOX_LIBRARY)
196+
ENDIF(APPLE)
197+
198+
IF(LIBFREENECT2_WITH_VT_SUPPORT)
199+
FIND_PACKAGE(TurboJPEG)
200+
ELSE()
201+
FIND_PACKAGE(TurboJPEG REQUIRED)
202+
ENDIF()
203+
204+
IF(TurboJPEG_FOUND)
205+
SET(LIBFREENECT2_WITH_TURBOJPEG_SUPPORT 1)
206+
207+
INCLUDE_DIRECTORIES(${TurboJPEG_INCLUDE_DIRS})
208+
209+
LIST(APPEND SOURCES
210+
src/turbo_jpeg_rgb_packet_processor.cpp
211+
)
212+
213+
LIST(APPEND LIBRARIES
214+
${TurboJPEG_LIBRARIES}
215+
)
216+
ENDIF()
217+
179218
SET(CMAKE_INSTALL_RPATH ${LibUSB_LIBDIR})
180219

181220
CONFIGURE_FILE("${MY_DIR}/include/libfreenect2/config.h.in" "${MY_DIR}/include/libfreenect2/config.h" @ONLY)

examples/protonect/include/libfreenect2/config.h.in

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

4444
#cmakedefine LIBFREENECT2_WITH_OPENCL_SUPPORT
4545

46+
#cmakedefine LIBFREENECT2_WITH_VT_SUPPORT
47+
48+
#cmakedefine LIBFREENECT2_WITH_TURBOJPEG_SUPPORT
49+
4650
#cmakedefine LIBFREENECT2_THREADING_STDLIB
4751

4852
#cmakedefine LIBFREENECT2_THREADING_TINYTHREAD

examples/protonect/include/libfreenect2/frame_listener.hpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,30 @@ class LIBFREENECT2_API Frame
4949
size_t width, height, bytes_per_pixel;
5050
unsigned char* data;
5151

52-
Frame(size_t width, size_t height, size_t bytes_per_pixel) :
52+
Frame(size_t width, size_t height, size_t bytes_per_pixel, unsigned char* _data = NULL) :
5353
width(width),
5454
height(height),
55-
bytes_per_pixel(bytes_per_pixel)
55+
bytes_per_pixel(bytes_per_pixel),
56+
rawdata(NULL),
57+
data(_data)
5658
{
57-
const size_t alignment = 64;
58-
size_t space = width * height * bytes_per_pixel + alignment;
59-
rawdata = new unsigned char[space];
60-
uintptr_t ptr = reinterpret_cast<uintptr_t>(rawdata);
61-
uintptr_t aligned = (ptr - 1u + alignment) & -alignment;
62-
data = reinterpret_cast<unsigned char *>(aligned);
59+
if (data == NULL)
60+
{
61+
const size_t alignment = 64;
62+
size_t space = width * height * bytes_per_pixel + alignment;
63+
rawdata = new unsigned char[space];
64+
uintptr_t ptr = reinterpret_cast<uintptr_t>(rawdata);
65+
uintptr_t aligned = (ptr - 1u + alignment) & -alignment;
66+
data = reinterpret_cast<unsigned char *>(aligned);
67+
}
6368
}
6469

65-
~Frame()
70+
virtual ~Frame()
6671
{
67-
delete[] rawdata;
72+
if (rawdata)
73+
{
74+
delete[] rawdata;
75+
}
6876
}
6977

7078
protected:

examples/protonect/include/libfreenect2/rgb_packet_processor.h

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

71+
#ifdef LIBFREENECT2_WITH_TURBOJPEG_SUPPORT
7172
class TurboJpegRgbPacketProcessorImpl;
7273

7374
class LIBFREENECT2_API TurboJpegRgbPacketProcessor : public RgbPacketProcessor
@@ -80,6 +81,22 @@ class LIBFREENECT2_API TurboJpegRgbPacketProcessor : public RgbPacketProcessor
8081
private:
8182
TurboJpegRgbPacketProcessorImpl *impl_;
8283
};
84+
#endif
85+
86+
#ifdef LIBFREENECT2_WITH_VT_SUPPORT
87+
class VTRgbPacketProcessorImpl;
88+
89+
class LIBFREENECT2_API VTRgbPacketProcessor : public RgbPacketProcessor
90+
{
91+
public:
92+
VTRgbPacketProcessor();
93+
virtual ~VTRgbPacketProcessor();
94+
protected:
95+
virtual void process(const libfreenect2::RgbPacket &packet);
96+
private:
97+
VTRgbPacketProcessorImpl *impl_;
98+
};
99+
#endif
83100

84101
} /* namespace libfreenect2 */
85102
#endif /* RGB_PACKET_PROCESSOR_H_ */

examples/protonect/src/packet_pipeline.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ void BasePacketPipeline::initialize()
3939
rgb_parser_ = new RgbPacketStreamParser();
4040
depth_parser_ = new DepthPacketStreamParser();
4141

42+
#ifdef LIBFREENECT2_WITH_VT_SUPPORT
43+
rgb_processor_ = new VTRgbPacketProcessor();
44+
#else
4245
rgb_processor_ = new TurboJpegRgbPacketProcessor();
46+
#endif
47+
4348
depth_processor_ = createDepthPacketProcessor();
4449

4550
async_rgb_processor_ = new AsyncPacketProcessor<RgbPacket>(rgb_processor_);
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)