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