@@ -55,33 +55,35 @@ void SnapshotManager::convert(uint64_t seqnum, QVideoFrame frame, WallClock time
5555 }catch (...){}
5656 }
5757
58- std::lock_guard<std::mutex> lg (m_lock);
59- // cout << "SnapshotManager::convert() - post convert: " << seqnum << endl;
60-
61- if (m_converted_seqnum < seqnum){
62- m_converted_seqnum = seqnum;
63- m_converted_snapshot = std::move (snapshot);
64- }
58+ {
59+ std::lock_guard<std::mutex> lg (m_lock);
60+ // cout << "SnapshotManager::convert() - post convert: " << seqnum << endl;
6561
66- m_active_conversions--;
62+ if (m_converted_seqnum < seqnum){
63+ push_new_screenshot (seqnum, std::move (snapshot));
64+ }
6765
68- if (m_queued_convert){
69- m_queued_convert = false ;
70- seqnum = m_cache.get_latest (frame, timestamp);
71- if (m_converting_seqnum < seqnum){
72- dispatch_conversion (seqnum, std::move (frame), timestamp);
66+ if (m_queued_convert){
67+ m_queued_convert = false ;
68+ seqnum = m_cache.get_latest (frame, timestamp);
69+ if (m_converting_seqnum < seqnum){
70+ dispatch_conversion (seqnum, std::move (frame), timestamp);
71+ }
7372 }
7473 }
7574
7675 cleanup ();
7776
78- // Warning: The moment we release the lock with (m_active_conversions == 0),
79- // this class can be immediately destructed.
77+ {
78+ std::lock_guard<std::mutex> lg (m_lock);
79+ m_active_conversions--;
8080
81- // Therefore it is not safe to notify after releasing the lock.
82- m_cv. notify_all ();
81+ // Warning: The moment we release the lock with (m_active_conversions == 0),
82+ // this class can be immediately destructed.
8383
84- // Lock is implicitly released here.
84+ // Therefore it is not safe to notify after releasing the lock.
85+ m_cv.notify_all ();
86+ }
8587}
8688bool SnapshotManager::try_dispatch_conversion (uint64_t seqnum, QVideoFrame frame, WallClock timestamp) noexcept {
8789 // Must call under the lock.
@@ -126,18 +128,49 @@ void SnapshotManager::dispatch_conversion(uint64_t seqnum, QVideoFrame frame, Wa
126128 m_active_conversions--;
127129 }
128130}
131+
132+ void SnapshotManager::push_new_screenshot (uint64_t seqnum, VideoSnapshot snapshot){
133+ m_converted_snapshot_archive[seqnum] = snapshot;
134+ m_converted_snapshot = std::move (snapshot);
135+ m_converted_seqnum = seqnum;
136+ }
129137void SnapshotManager::cleanup (){
130- // Must call under the lock.
138+ // We do this in 2 passes. First we walk through both sets and move all the
139+ // stale objects out. Then we release the lock and destroy all the stale
140+ // objects. This minimizes the amount of time the lock is held.
141+
142+ std::vector<std::unique_ptr<AsyncTask>> tasks_to_free;
143+ std::vector<VideoSnapshot> snapshots_to_free;
144+
145+ // Pass 1: Move all stale objects out.
146+ {
147+ std::lock_guard<std::mutex> lg (m_lock);
148+
149+ // Cleanup finished tasks.
150+ while (!m_pending_conversions.empty ()){
151+ auto iter = m_pending_conversions.begin ();
152+ if (iter->second ->is_finished ()){
153+ tasks_to_free.emplace_back (std::move (iter->second ));
154+ m_pending_conversions.erase (iter);
155+ }else {
156+ break ;
157+ }
158+ }
131159
132- // Cleanup finished tasks.
133- while (!m_pending_conversions.empty ()){
134- auto iter = m_pending_conversions.begin ();
135- if (iter->second ->is_finished ()){
136- m_pending_conversions.erase (iter);
137- }else {
138- break ;
160+ // Walk through the snapshot archive and clear out everything with only
161+ // one reference.
162+ for (auto iter = m_converted_snapshot_archive.begin (); iter != m_converted_snapshot_archive.end ();){
163+ if (iter->second .frame .use_count () <= 1 ){
164+ snapshots_to_free.emplace_back (std::move (iter->second ));
165+ iter = m_converted_snapshot_archive.erase (iter);
166+ }else {
167+ ++iter;
168+ }
139169 }
140170 }
171+
172+ // Pass 2: Destroy the stale objects.
173+ // Implicitly destroyed here.
141174}
142175
143176
@@ -169,7 +202,6 @@ VideoSnapshot SnapshotManager::snapshot_latest_blocking(){
169202 WallClock timestamp;
170203 seqnum = m_cache.get_latest (frame, timestamp);
171204
172- // m_active_conversions++;
173205 m_converting_seqnum = seqnum;
174206
175207 VideoSnapshot snapshot;
@@ -183,17 +215,14 @@ VideoSnapshot SnapshotManager::snapshot_latest_blocking(){
183215 microseconds = (uint32_t )std::chrono::duration_cast<std::chrono::microseconds>(time1 - time0).count ();
184216 }
185217 m_stats_conversion.report_data (m_logger, microseconds);
186- // m_active_conversions--;
187218 }catch (...){
188- // m_active_conversions--;
189219 m_logger.log (" Exception thrown while converting QVideoFrame -> QImage." , COLOR_RED);
190220 throw ;
191221 }
192222
193- m_converted_seqnum = seqnum;
194223
195224 if (timestamp > m_converted_snapshot.timestamp ){
196- m_converted_snapshot = std::move (snapshot);
225+ push_new_screenshot (seqnum, std::move (snapshot) );
197226 m_cv.notify_all ();
198227 }
199228
@@ -232,22 +261,6 @@ VideoSnapshot SnapshotManager::snapshot_recent_nonblocking(WallClock min_time){
232261// cout << "snapshot_recent_nonblocking(): Too old..." << endl;
233262 return VideoSnapshot ();
234263 }
235-
236- #if 0
237- std::chrono::microseconds window(m_stats_conversion.max());
238- // cout << "window = " << window.count() << endl;
239-
240- WallClock oldest_allowed = now - 2 * window;
241- // cout << "snapshot_recent_nonblocking(): " << m_converted_seqnum << endl;
242-
243- if (m_converted_snapshot.timestamp >= oldest_allowed){
244- // cout << "snapshot_recent_nonblocking(): Good..." << endl;
245- return m_converted_snapshot;
246- }
247-
248- // cout << "snapshot_recent_nonblocking(): Too old..." << endl;
249- return VideoSnapshot();
250- #endif
251264}
252265
253266
0 commit comments