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
5153void 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
0 commit comments