Skip to content

Commit 275d7f9

Browse files
committed
New VideoToolbox rgb packet processor
Mac OS X >= 10.8 has hardware accelerated jpeg decoding (a bit hidden)
1 parent 01a12f8 commit 275d7f9

File tree

6 files changed

+286
-14
lines changed

6 files changed

+286
-14
lines changed

examples/protonect/CMakeLists.txt

Lines changed: 39 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

@@ -169,6 +165,45 @@ IF(ENABLE_OPENCL)
169165
ENDIF(OPENCL_FOUND)
170166
ENDIF(ENABLE_OPENCL)
171167

168+
IF(APPLE)
169+
FIND_LIBRARY(VIDEOTOOLBOX_LIBRARY VideoToolbox)
170+
171+
IF(VIDEOTOOLBOX_LIBRARY)
172+
SET(LIBFREENECT2_WITH_VT_SUPPORT 1)
173+
174+
FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED)
175+
FIND_LIBRARY(COREMEDIA_LIBRARY CoreMedia REQUIRED)
176+
FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo REQUIRED)
177+
178+
LIST(APPEND SOURCES
179+
src/vt_rgb_packet_processor.cpp
180+
)
181+
182+
LIST(APPEND LIBRARIES
183+
${VIDEOTOOLBOX_LIBRARY}
184+
${COREFOUNDATION_LIBRARY}
185+
${COREMEDIA_LIBRARY}
186+
${COREVIDEO_LIBRARY}
187+
)
188+
ENDIF(VIDEOTOOLBOX_LIBRARY)
189+
ENDIF(APPLE)
190+
191+
IF(NOT(APPLE) OR NOT(LIBFREENECT2_WITH_VT_SUPPORT))
192+
FIND_PACKAGE(TurboJPEG REQUIRED) #does not provide a package-config file
193+
194+
SET(LIBFREENECT2_WITH_TURBOJPEG_SUPPORT 1)
195+
196+
INCLUDE_DIRECTORIES(${TurboJPEG_INCLUDE_DIRS})
197+
198+
LIST(APPEND SOURCES
199+
src/turbo_jpeg_rgb_packet_processor.cpp
200+
)
201+
202+
LIST(APPEND LIBRARIES
203+
${TurboJPEG_LIBRARIES}
204+
)
205+
ENDIF()
206+
172207
SET(CMAKE_INSTALL_RPATH ${LibUSB_LIBDIR})
173208

174209
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_TURBOJPEG_SUPPORT
4243
rgb_processor_ = new TurboJpegRgbPacketProcessor();
44+
#elif defined(LIBFREENECT2_WITH_VT_SUPPORT)
45+
rgb_processor_ = new VTRgbPacketProcessor();
46+
#endif
47+
4348
depth_processor_ = createDepthPacketProcessor();
4449

4550
async_rgb_processor_ = new AsyncPacketProcessor<RgbPacket>(rgb_processor_);
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
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+
30+
#include <VideoToolbox/VideoToolbox.h>
31+
#include <iostream>
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
62+
{
63+
public:
64+
CMFormatDescriptionRef format;
65+
VTDecompressionSessionRef decoder;
66+
67+
double timing_acc;
68+
double timing_acc_n;
69+
70+
Timer timer;
71+
72+
VTRgbPacketProcessorImpl() {
73+
timing_acc = 0.0;
74+
timing_acc_n = 0.0;
75+
76+
int32_t width = 1920, height = 1080;
77+
78+
CMVideoFormatDescriptionCreate(NULL, kCMVideoCodecType_JPEG, width, height, nil, &format);
79+
80+
const void *decoderSpecificationKeys[] = {kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder};
81+
const void *decoderSpecificationValues[] = {kCFBooleanTrue};
82+
CFDictionaryRef decoderSpecification = CFDictionaryCreate(NULL,
83+
decoderSpecificationKeys,
84+
decoderSpecificationValues,
85+
1,
86+
&kCFTypeDictionaryKeyCallBacks,
87+
&kCFTypeDictionaryValueCallBacks);
88+
89+
int32_t pixelFormat = kCVPixelFormatType_32BGRA;
90+
const void *outputKeys[] = {kCVPixelBufferPixelFormatTypeKey, kCVPixelBufferWidthKey, kCVPixelBufferHeightKey};
91+
const void *outputValues[] =
92+
{CFNumberCreate(NULL, kCFNumberSInt32Type, &pixelFormat), CFNumberCreate(NULL, kCFNumberSInt32Type, &width),
93+
CFNumberCreate(NULL, kCFNumberSInt32Type, &height)};
94+
95+
CFDictionaryRef outputConfiguration = CFDictionaryCreate(NULL,
96+
outputKeys,
97+
outputValues,
98+
3,
99+
&kCFTypeDictionaryKeyCallBacks,
100+
&kCFTypeDictionaryValueCallBacks);
101+
102+
VTDecompressionOutputCallbackRecord callback = {&VTRgbPacketProcessorImpl::decodeFrame, NULL};
103+
104+
VTDecompressionSessionCreate(NULL, format, decoderSpecification, outputConfiguration, &callback, &decoder);
105+
106+
CFRelease(decoderSpecification);
107+
CFRelease(outputConfiguration);
108+
}
109+
110+
~VTRgbPacketProcessorImpl() {
111+
VTDecompressionSessionInvalidate(decoder);
112+
CFRelease(decoder);
113+
CFRelease(format);
114+
}
115+
116+
static void decodeFrame(void *decompressionOutputRefCon,
117+
void *sourceFrameRefCon,
118+
OSStatus status,
119+
VTDecodeInfoFlags infoFlags,
120+
CVImageBufferRef pixelBuffer,
121+
CMTime presentationTimeStamp,
122+
CMTime presentationDuration) {
123+
CVPixelBufferRef *outputPixelBuffer = (CVPixelBufferRef *) sourceFrameRefCon;
124+
*outputPixelBuffer = CVPixelBufferRetain(pixelBuffer);
125+
}
126+
127+
void startTiming() {
128+
timer.start();
129+
}
130+
131+
void stopTiming() {
132+
timing_acc += timer.stop();
133+
timing_acc_n += 1.0;
134+
135+
if (timing_acc_n >= 100.0) {
136+
double avg = (timing_acc / timing_acc_n);
137+
std::cout << "[VTRgbPacketProcessor] avg. time: " << (avg * 1000) << "ms -> ~" << (1.0 / avg) << "Hz"
138+
<< std::endl;
139+
timing_acc = 0.0;
140+
timing_acc_n = 0.0;
141+
}
142+
}
143+
};
144+
145+
VTRgbPacketProcessor::VTRgbPacketProcessor() :
146+
impl_(new VTRgbPacketProcessorImpl())
147+
{
148+
}
149+
150+
VTRgbPacketProcessor::~VTRgbPacketProcessor()
151+
{
152+
delete impl_;
153+
}
154+
155+
void VTRgbPacketProcessor::process(const RgbPacket &packet)
156+
{
157+
if (listener_ != 0) {
158+
impl_->startTiming();
159+
160+
CMBlockBufferRef blockBuffer;
161+
CMBlockBufferCreateWithMemoryBlock(
162+
NULL,
163+
packet.jpeg_buffer,
164+
packet.jpeg_buffer_length,
165+
kCFAllocatorNull,
166+
NULL,
167+
0,
168+
packet.jpeg_buffer_length,
169+
0,
170+
&blockBuffer
171+
);
172+
173+
CMSampleBufferRef sampleBuffer;
174+
CMSampleBufferCreateReady(
175+
NULL,
176+
blockBuffer,
177+
impl_->format,
178+
1,
179+
0,
180+
NULL,
181+
0,
182+
NULL,
183+
&sampleBuffer
184+
);
185+
186+
CVPixelBufferRef pixelBuffer = NULL;
187+
VTDecompressionSessionDecodeFrame(impl_->decoder, sampleBuffer, 0, &pixelBuffer, NULL);
188+
189+
Frame *frame = new VTFrame(1920, 1080, 4, pixelBuffer);
190+
191+
frame->timestamp = packet.timestamp;
192+
frame->sequence = packet.sequence;
193+
194+
listener_->onNewFrame(Frame::Color, frame);
195+
196+
CFRelease(sampleBuffer);
197+
CFRelease(blockBuffer);
198+
199+
impl_->stopTiming();
200+
}
201+
}
202+
203+
} /* namespace libfreenect2 */

0 commit comments

Comments
 (0)