Skip to content

Commit d70c94e

Browse files
MathieuFavreaualexmo16
authored andcommitted
Fix cuda compilation and output display bugs (#103)
1 parent 702d572 commit d70c94e

File tree

13 files changed

+216
-137
lines changed

13 files changed

+216
-137
lines changed

c_plus_plus/src/model/stream/media_thread.cpp

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#include "media_thread.h"
22

3+
#include <cstring>
34
#include <iostream>
45

56
#include "model/audio_suppresser/audio_suppresser.h"
67
#include "model/classifier/classifier.h"
78
#include "model/stream/utils/alloc/heap_object_factory.h"
9+
#include "model/stream/utils/models/circular_buffer.h"
810
#include "model/stream/utils/models/point.h"
911
#include "model/stream/video/dewarping/dewarping_helper.h"
1012
#include "model/stream/video/video_stabilizer.h"
@@ -50,6 +52,20 @@ MediaThread::MediaThread(std::unique_ptr<IAudioSource> audioSource, std::unique_
5052

5153
void MediaThread::run()
5254
{
55+
// Utilitary objects
56+
HeapObjectFactory heapObjectFactory;
57+
DisplayImageBuilder displayImageBuilder(videoOutputConfig_.resolution);
58+
VideoStabilizer videoStabilizer(videoInputConfig_.fpsTarget);
59+
60+
// Display images
61+
Image emptyDisplay(videoOutputConfig_.resolution, videoOutputConfig_.imageFormat);
62+
CircularBuffer<Image> displayBuffers(2, Image(videoOutputConfig_.resolution, videoOutputConfig_.imageFormat));
63+
64+
// Virtual cameras images
65+
const Dim2<int>& maxVcDim = displayImageBuilder.getMaxVirtualCameraDim();
66+
std::vector<Image> vcImages(1, RGBImage(maxVcDim.width, maxVcDim.height));
67+
std::vector<Image> vcOutputFormatImages(1, Image(maxVcDim.width, maxVcDim.height, videoOutputConfig_.imageFormat));
68+
5369
// TODO: config?
5470
const int classifierRangeThreshold = 2;
5571

@@ -58,93 +74,115 @@ void MediaThread::run()
5874

5975
try
6076
{
61-
audioSource_->open();
62-
audioSink_->open();
63-
positionSource_->open();
77+
// Allocate display images
78+
heapObjectFactory.allocateObject(emptyDisplay);
79+
heapObjectFactory.allocateObjectCircularBuffer(displayBuffers);
6480

65-
HeapObjectFactory heapObjectFactory;
66-
DualBuffer<Image> displayBuffers(Image(videoOutputConfig_.resolution, videoOutputConfig_.imageFormat));
67-
DisplayImageBuilder displayImageBuilder(videoOutputConfig_.resolution);
81+
// Allocate virtual camera images
82+
objectFactory_->allocateObjectVector(vcImages);
83+
objectFactory_->allocateObjectVector(vcOutputFormatImages);
6884

69-
heapObjectFactory.allocateObjectDualBuffer(displayBuffers);
70-
displayImageBuilder.setDisplayImageColor(displayBuffers.getCurrent());
71-
displayImageBuilder.setDisplayImageColor(displayBuffers.getInUse());
85+
// Set background color of empty display
86+
displayImageBuilder.setDisplayImageColor(emptyDisplay);
7287

73-
Dim2<int> maxVcDim = displayImageBuilder.getMaxVirtualCameraDim();
74-
std::vector<Image> vcImages(5, RGBImage(maxVcDim.width, maxVcDim.height));
75-
objectFactory_->allocateObjectVector(vcImages);
88+
// Start audio resources
89+
audioSource_->open();
90+
audioSink_->open();
91+
positionSource_->open();
7692

7793
Point<float> fisheyeCenter(videoInputConfig_.resolution.width / 2.f, videoInputConfig_.resolution.height / 2.f);
7894
std::vector<SphericalAngleRect> detections;
7995

80-
VideoStabilizer videoStabilizer(videoInputConfig_.fpsTarget);
81-
8296
// Media loop start
83-
8497
std::cout << "MediaThread loop started" << std::endl;
8598

8699
while (!isAbortRequested())
87100
{
88101
videoStabilizer.startFrame();
89102

103+
// Try to get queued detections
90104
if (detectionQueue_->try_dequeue(detections))
91105
{
92106
virtualCameraManager_->updateVirtualCamerasGoal(detections);
93107
}
94108

109+
// Update the position and size of virtual cameras
95110
virtualCameraManager_->updateVirtualCameras(videoStabilizer.getLastFrameTimeMs());
96111

112+
// Read audio source and positions
97113
int audioBytesRead = audioSource_->read(audioBuffer, sizeof(audioBuffer));
98114
std::vector<SourcePosition> sourcePositions = positionSource_->getPositions();
99115

116+
// Read image from video input and convert it to rgb format for dewarping
100117
const Image& rawImage = videoInput_->readImage();
101118
const Image& rgbImage = imageBuffer_->getCurrent();
102119
imageConverter_->convert(rawImage, rgbImage);
103120
imageBuffer_->swap();
104121

122+
// Get the active virtual cameras
105123
const std::vector<VirtualCamera> virtualCameras = virtualCameraManager_->getVirtualCameras();
106-
int vcCount = (int)virtualCameras.size();
124+
int vcCount = static_cast<int>(virtualCameras.size());
107125

126+
// If there are active virtual cameras, dewarp images of each vc and combine them in an output image
108127
if (vcCount > 0)
109128
{
110-
// This should not happend often in theory, it's only if a large amount of virtual camera are required
129+
// Dynamically allocate more virtual camera images
111130
for (int i = vcImages.size(); i < vcCount; ++i)
112131
{
113132
RGBImage vcImage(maxVcDim.width, maxVcDim.height);
114133
objectFactory_->allocateObject(vcImage);
115134
vcImages.push_back(vcImage);
135+
136+
Image vcOutputFormatImage(maxVcDim.width, maxVcDim.height, videoOutputConfig_.imageFormat);
137+
objectFactory_->allocateObject(vcOutputFormatImage);
138+
vcOutputFormatImages.push_back(vcOutputFormatImage);
116139
}
117140

141+
// Get the size of the virtual camera images to dewarp (this is to prevent resize in the output format)
118142
Dim2<int> resizeDim(displayImageBuilder.getVirtualCameraDim(vcCount));
119143
std::vector<Image> vcResizeImages(vcCount, RGBImage(resizeDim));
144+
std::vector<Image> vcResizeOutputFormatImages(vcCount,
145+
Image(resizeDim, videoOutputConfig_.imageFormat));
120146

147+
// Virtual camera dewarping loop
121148
for (int i = 0; i < vcCount; ++i)
122149
{
123-
const VirtualCamera& virtualCamera = virtualCameras[i];
150+
// Use the same buffers as vcImages for the smaller dewarped images
124151
Image& vcResizeImage = vcResizeImages[i];
125152
vcResizeImage.hostData = vcImages[i].hostData;
126153
vcResizeImage.deviceData = vcImages[i].deviceData;
127154

155+
// Dewarping of virtual camera
156+
const VirtualCamera& virtualCamera = virtualCameras[i];
128157
DewarpingParameters vcParams =
129158
getDewarpingParametersFromAngleBoundingBox(virtualCamera, fisheyeCenter, dewarpingConfig_);
130159
dewarper_->dewarpImageFiltered(rgbImage, vcResizeImage, vcParams);
131160

132-
// Ok, this is a hack until we work with raw data for dewarping of virtual cameras (convert on
133-
// itself, only work from RGB)
134-
Image inImage = vcResizeImage;
135-
vcResizeImages[i] = Image(inImage.width, inImage.height, videoOutputConfig_.imageFormat);
136-
vcResizeImages[i].deviceData = inImage.deviceData;
137-
vcResizeImages[i].hostData = inImage.hostData;
138-
imageConverter_->convert(inImage, vcResizeImage);
161+
// Use the same buffers as vcOutputFormatImages for the smaller dewarped (and converted) images
162+
Image& vcResizeOutputFormatImage = vcResizeOutputFormatImages[i];
163+
vcResizeOutputFormatImage.hostData = vcOutputFormatImages[i].hostData;
164+
vcResizeOutputFormatImage.deviceData = vcOutputFormatImages[i].deviceData;
165+
166+
// Conversion from rgb to output format
167+
imageConverter_->convert(vcResizeImage, vcResizeOutputFormatImage);
139168
}
140169

141-
const Image& displayImage = displayBuffers.getCurrent();
142-
displayImageBuilder.clearVirtualCamerasOnDisplayImage(displayImage);
170+
// Clear the image before writting to it
171+
const Image& displayImage = displayBuffers.current();
172+
std::memcpy(displayImage.hostData, emptyDisplay.hostData, displayImage.size);
143173

174+
// Wait for dewarping to be completed
144175
synchronizer_->sync();
145-
displayImageBuilder.createDisplayImage(vcResizeImages, displayImage);
176+
177+
// Write to output image and send it to the video output
178+
displayImageBuilder.createDisplayImage(vcResizeOutputFormatImages, displayImage);
146179
videoOutput_->writeImage(displayImage);
147-
displayBuffers.swap();
180+
displayBuffers.next();
181+
}
182+
else
183+
{
184+
// If there are no active virtual cameras, just send an empty image
185+
videoOutput_->writeImage(emptyDisplay);
148186
}
149187

150188
if (audioBytesRead > 0)
@@ -166,23 +204,29 @@ void MediaThread::run()
166204

167205
detections.clear();
168206

207+
// If the frame took less than 1/fps, this call will block to match frame time of 1/fps
169208
videoStabilizer.endFrame();
170209
}
171-
172-
heapObjectFactory.deallocateObjectDualBuffer(displayBuffers);
173-
objectFactory_->deallocateObjectVector(vcImages);
174210
}
175211
catch (const std::exception& e)
176212
{
177-
std::cout << e.what() << std::endl;
213+
std::cout << "Error in video thread : " << e.what() << std::endl;
178214
}
179215

216+
// Clean audio resources
180217
audioSource_->close();
181218
audioSink_->close();
182219
positionSource_->close();
183-
184220
delete[] audioBuffer;
185221

222+
// Deallocate display images
223+
heapObjectFactory.deallocateObject(emptyDisplay);
224+
heapObjectFactory.deallocateObjectCircularBuffer(displayBuffers);
225+
226+
// Deallocate virtual camera images
227+
objectFactory_->deallocateObjectVector(vcImages);
228+
objectFactory_->deallocateObjectVector(vcOutputFormatImages);
229+
186230
std::cout << "MediaThread loop finished" << std::endl;
187231
}
188232
} // namespace Model

c_plus_plus/src/model/stream/stream.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ Stream::Stream(const VideoConfig& videoInputConfig, const VideoConfig& videoOutp
2828
, dewarpingConfig_(dewarpingConfig)
2929
, mediaThread_(nullptr)
3030
, detectionThread_(nullptr)
31+
, implementationFactory_(false)
3132
{
32-
bool useZeroCopyIfSupported = false;
3333
int detectionDewarpingCount = 4;
3434
float aspectRatio = 3.f / 4.f;
3535
float minElevation = math::deg2rad(0.f);
@@ -57,24 +57,22 @@ Stream::Stream(const VideoConfig& videoInputConfig, const VideoConfig& videoOutp
5757
std::string weightsFile = root + "/config/yolo/weights/yolov3-tiny.weights";
5858
std::string metaFile = root + "/config/yolo/cfg/coco.data";
5959

60-
ImplementationFactory implementationFactory(useZeroCopyIfSupported);
61-
62-
objectFactory_ = implementationFactory.getDetectionObjectFactory();
60+
objectFactory_ = implementationFactory_.getDetectionObjectFactory();
6361
objectFactory_->allocateObjectLockTripleBuffer(*imageBuffer_);
6462

6563
detectionThread_ = std::make_unique<DetectionThread>(
66-
imageBuffer_, implementationFactory.getDetector(configFile, weightsFile, metaFile), detectionQueue,
67-
implementationFactory.getDetectionFisheyeDewarper(aspectRatio),
68-
implementationFactory.getDetectionObjectFactory(), implementationFactory.getDetectionSynchronizer(),
64+
imageBuffer_, implementationFactory_.getDetector(configFile, weightsFile, metaFile), detectionQueue,
65+
implementationFactory_.getDetectionFisheyeDewarper(aspectRatio),
66+
implementationFactory_.getDetectionObjectFactory(), implementationFactory_.getDetectionSynchronizer(),
6967
dewarpingConfig_, detectionDewarpingCount);
7068

7169
mediaThread_ = std::make_unique<MediaThread>(
7270
std::make_unique<OdasAudioSource>(10030), std::make_unique<PulseAudioSink>(audioOutputConfig_),
73-
std::make_unique<OdasPositionSource>(10020), implementationFactory.getCameraReader(videoInputConfig_),
74-
implementationFactory.getFisheyeDewarper(), implementationFactory.getObjectFactory(),
75-
std::make_unique<VirtualCameraOutput>(videoOutputConfig_), implementationFactory.getSynchronizer(),
71+
std::make_unique<OdasPositionSource>(10020), implementationFactory_.getCameraReader(videoInputConfig_),
72+
implementationFactory_.getFisheyeDewarper(), implementationFactory_.getObjectFactory(),
73+
std::make_unique<VirtualCameraOutput>(videoOutputConfig_), implementationFactory_.getSynchronizer(),
7674
std::make_unique<VirtualCameraManager>(aspectRatio, minElevation, maxElevation), detectionQueue, imageBuffer_,
77-
implementationFactory.getImageConverter(), dewarpingConfig_, videoInputConfig_, videoOutputConfig_,
75+
implementationFactory_.getImageConverter(), dewarpingConfig_, videoInputConfig_, videoOutputConfig_,
7876
audioInputConfig_, audioOutputConfig_);
7977
}
8078

@@ -97,4 +95,4 @@ void Stream::stop()
9795
mediaThread_->join();
9896
}
9997

100-
} // namespace Model
98+
} // namespace Model

c_plus_plus/src/model/stream/stream.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "model/stream/utils/alloc/i_object_factory.h"
1010
#include "model/stream/video/detection/detection_thread.h"
1111
#include "model/stream/video/dewarping/models/dewarping_config.h"
12+
#include "model/stream/video/impl/implementation_factory.h"
1213
#include "model/stream/video/video_config.h"
1314

1415
namespace Model
@@ -35,6 +36,7 @@ class Stream : public IStream
3536
std::unique_ptr<DetectionThread> detectionThread_;
3637
std::unique_ptr<IObjectFactory> objectFactory_;
3738
std::shared_ptr<LockTripleBuffer<Image>> imageBuffer_;
39+
ImplementationFactory implementationFactory_;
3840
};
3941

4042
} // namespace Model

c_plus_plus/src/model/stream/utils/alloc/i_object_factory.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <vector>
55

66
#include "model/stream/utils/images/images.h"
7+
#include "model/stream/utils/models/circular_buffer.h"
78
#include "model/stream/utils/models/dual_buffer.h"
89
#include "model/stream/utils/threads/lock_triple_buffer.h"
910
#include "model/stream/video/dewarping/models/dewarping_mapping.h"
@@ -37,6 +38,26 @@ class IObjectFactory
3738
deallocateObject(buffer.getInUse());
3839
}
3940

41+
template <typename T>
42+
void allocateObjectCircularBuffer(CircularBuffer<T>& buffer) const
43+
{
44+
for (std::size_t i = 0; i < buffer.size(); ++i)
45+
{
46+
allocateObject(buffer.current());
47+
buffer.next();
48+
}
49+
}
50+
51+
template <typename T>
52+
void deallocateObjectCircularBuffer(CircularBuffer<T>& buffer) const
53+
{
54+
for (std::size_t i = 0; i < buffer.size(); ++i)
55+
{
56+
deallocateObject(buffer.current());
57+
buffer.next();
58+
}
59+
}
60+
4061
template <typename T>
4162
void allocateObjectLockTripleBuffer(LockTripleBuffer<T>& buffer) const
4263
{

c_plus_plus/src/model/stream/utils/models/circular_buffer.h

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef CIRCULAR_BUFFER_H
22
#define CIRCULAR_BUFFER_H
33

4-
#include <memory>
4+
#include <vector>
55

66
namespace Model
77
{
@@ -11,25 +11,16 @@ class CircularBuffer
1111
public:
1212
explicit CircularBuffer(std::size_t size, const T& value = T())
1313
: size_(size)
14-
, buffers_(std::make_unique<T[]>(size))
14+
, buffers_(size, value)
1515
, index_(0)
1616
{
17-
for (std::size_t i = 0; i < size_; ++i)
18-
{
19-
buffers_[i] = value;
20-
}
2117
}
2218

2319
std::size_t size()
2420
{
2521
return size_;
2622
}
2723

28-
const std::unique_ptr<T[]>& buffers()
29-
{
30-
return buffers_;
31-
}
32-
3324
T& current()
3425
{
3526
return buffers_[index_];
@@ -42,7 +33,7 @@ class CircularBuffer
4233

4334
private:
4435
std::size_t size_;
45-
std::unique_ptr<T[]> buffers_;
36+
std::vector<T> buffers_;
4637
int index_;
4738
};
4839

c_plus_plus/src/model/stream/video/input/camera_reader.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ CameraReader::CameraReader(const VideoConfig& videoConfig, std::size_t bufferCou
4848

4949
CameraReader::~CameraReader()
5050
{
51-
const std::unique_ptr<IndexedImage[]>& buffers = images_.buffers();
5251
for (std::size_t i = 0; i < images_.size(); ++i)
5352
{
54-
unmapBuffer(buffers[i]);
53+
unmapBuffer(images_.current());
54+
images_.next();
5555
}
5656

5757
close(fd_);
@@ -124,10 +124,10 @@ void CameraReader::requestBuffers(std::size_t bufferCount)
124124
throw std::runtime_error("Failed to request buffers for camera " + videoConfig_.deviceName);
125125
}
126126

127-
const std::unique_ptr<IndexedImage[]>& buffers = images_.buffers();
128127
for (std::size_t i = 0; i < images_.size(); ++i)
129128
{
130-
mapBuffer(buffers[i]);
129+
mapBuffer(images_.current());
130+
images_.next();
131131
}
132132
}
133133

@@ -213,9 +213,9 @@ void CameraReader::setImageFormat()
213213
else if (fmt.fmt.pix.width != (unsigned int)videoConfig_.resolution.width ||
214214
fmt.fmt.pix.height != (unsigned int)videoConfig_.resolution.height)
215215
{
216-
throw std::runtime_error("Camera does not support specified image size : " +
217-
std::to_string(videoConfig_.resolution.width) + " x " +
218-
std::to_string(videoConfig_.resolution.height));
216+
throw std::runtime_error(
217+
"Camera does not support specified image size : " + std::to_string(videoConfig_.resolution.width) + " x " +
218+
std::to_string(videoConfig_.resolution.height));
219219
}
220220
else
221221
{

0 commit comments

Comments
 (0)