Commit 6e844a9c9f2d0cb2b73ca1a184d0099eb01791c0

Authored by Charles Otto
1 parent fbd840a0

Update handling of FTE

If a transform sets FTE on a template, don't pass that on to subsequent
transforms. This is done by placing checks after every project call by stream
and pipe. Switch the FTE marker from metadata to a member variable of template.
openbr/core/core.cpp
@@ -195,13 +195,11 @@ struct AlgorithmCore @@ -195,13 +195,11 @@ struct AlgorithmCore
195 if (fileExclusion) 195 if (fileExclusion)
196 outputDesc = "FileExclusion(" + gallery.flat() + ")+"; 196 outputDesc = "FileExclusion(" + gallery.flat() + ")+";
197 outputDesc.append("GalleryOutput("+gallery.flat()+")"); 197 outputDesc.append("GalleryOutput("+gallery.flat()+")");
198 - QScopedPointer<Transform> outputTform(Transform::make(outputDesc, NULL));  
199 - stages.append(outputTform.data());  
200 stages.append(progressCounter.data()); 198 stages.append(progressCounter.data());
201 199
202 QScopedPointer<Transform> pipeline(br::pipeTransforms(stages)); 200 QScopedPointer<Transform> pipeline(br::pipeTransforms(stages));
203 201
204 - QScopedPointer<Transform> stream(br::wrapTransform(pipeline.data(), "Stream(readMode=StreamGallery, endPoint=DiscardTemplates)")); 202 + QScopedPointer<Transform> stream(br::wrapTransform(pipeline.data(), "Stream(readMode=StreamGallery, endPoint="+outputDesc+"+DiscardTemplates)"));
205 203
206 TemplateList data, output; 204 TemplateList data, output;
207 data.append(input); 205 data.append(input);
@@ -479,8 +477,6 @@ struct AlgorithmCore @@ -479,8 +477,6 @@ struct AlgorithmCore
479 // output specification we were passed. Gallery metadata is necessary for some Outputs to function correctly. 477 // output specification we were passed. Gallery metadata is necessary for some Outputs to function correctly.
480 QString outputString = output.flat().isEmpty() ? "Empty" : output.flat(); 478 QString outputString = output.flat().isEmpty() ? "Empty" : output.flat();
481 QString outputRegionDesc = "Output("+ outputString +"," + targetGallery.flat() +"," + queryGallery.flat() + ","+ QString::number(transposeMode ? 1 : 0) + ")"; 479 QString outputRegionDesc = "Output("+ outputString +"," + targetGallery.flat() +"," + queryGallery.flat() + ","+ QString::number(transposeMode ? 1 : 0) + ")";
482 - QScopedPointer<Transform> outputTForm(Transform::make(outputRegionDesc,NULL));  
483 - compareOutput.append(outputTForm.data());  
484 480
485 // The ProgressCounter transform will simply provide a display about the number of rows completed. 481 // The ProgressCounter transform will simply provide a display about the number of rows completed.
486 compareOutput.append(progressCounter.data()); 482 compareOutput.append(progressCounter.data());
@@ -491,7 +487,7 @@ struct AlgorithmCore @@ -491,7 +487,7 @@ struct AlgorithmCore
491 487
492 // Now, we will give that base transform to a stream, which will incrementally read the row gallery 488 // Now, we will give that base transform to a stream, which will incrementally read the row gallery
493 // and pass the transforms it reads through the base algorithm. 489 // and pass the transforms it reads through the base algorithm.
494 - QScopedPointer<Transform> streamWrapper(br::wrapTransform(pipeline, "Stream(readMode=StreamGallery, endPoint=DiscardTemplates)")); 490 + QScopedPointer<Transform> streamWrapper(br::wrapTransform(pipeline, "Stream(readMode=StreamGallery, endPoint="+outputRegionDesc+"+DiscardTemplates)"));
495 491
496 // We set up a template containing the rowGallery we want to compare. 492 // We set up a template containing the rowGallery we want to compare.
497 TemplateList rowGalleryTemplate; 493 TemplateList rowGalleryTemplate;
openbr/openbr_plugin.cpp
@@ -261,6 +261,7 @@ void File::appendRects(const QList&lt;cv::Rect&gt; &amp;rects) @@ -261,6 +261,7 @@ void File::appendRects(const QList&lt;cv::Rect&gt; &amp;rects)
261 /* File - private methods */ 261 /* File - private methods */
262 void File::init(const QString &file) 262 void File::init(const QString &file)
263 { 263 {
  264 + fte = false;
264 name = file; 265 name = file;
265 266
266 while (name.endsWith(']') || name.endsWith(')')) { 267 while (name.endsWith(']') || name.endsWith(')')) {
@@ -287,6 +288,11 @@ void File::init(const QString &amp;file) @@ -287,6 +288,11 @@ void File::init(const QString &amp;file)
287 } 288 }
288 name = name.left(index); 289 name = name.left(index);
289 } 290 }
  291 +
  292 + if (contains("FTE")) {
  293 + fte = getBool("FTE");
  294 + remove("FTE");
  295 + }
290 } 296 }
291 297
292 /* File - global methods */ 298 /* File - global methods */
@@ -367,7 +373,7 @@ int FileList::failures() const @@ -367,7 +373,7 @@ int FileList::failures() const
367 { 373 {
368 int failures = 0; 374 int failures = 0;
369 foreach (const File &file, *this) 375 foreach (const File &file, *this)
370 - if (file.get<bool>("FTO", false) || file.get<bool>("FTE", false)) 376 + if (file.fte)
371 failures++; 377 failures++;
372 return failures; 378 return failures;
373 } 379 }
@@ -1344,7 +1350,7 @@ static void _project(const Transform *transform, const Template *src, Template * @@ -1344,7 +1350,7 @@ static void _project(const Transform *transform, const Template *src, Template *
1344 } catch (...) { 1350 } catch (...) {
1345 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName())); 1351 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName()));
1346 *dst = Template(src->file); 1352 *dst = Template(src->file);
1347 - dst->file.set("FTE", true); 1353 + dst->file.fte = true;
1348 } 1354 }
1349 } 1355 }
1350 1356
@@ -1474,6 +1480,9 @@ float Distance::compare(const Template &amp;a, const Template &amp;b) const @@ -1474,6 +1480,9 @@ float Distance::compare(const Template &amp;a, const Template &amp;b) const
1474 1480
1475 float Distance::compare(const cv::Mat &a, const cv::Mat &b) const 1481 float Distance::compare(const cv::Mat &a, const cv::Mat &b) const
1476 { 1482 {
  1483 + if (a.empty() || b.empty() || a.rows != b.rows || a.cols != b.cols || a.elemSize() != b.elemSize())
  1484 + return -std::numeric_limits<float>::max();
  1485 +
1477 return compare(a.data, b.data, a.rows * a.cols * a.elemSize()); 1486 return compare(a.data, b.data, a.rows * a.cols * a.elemSize());
1478 } 1487 }
1479 1488
openbr/openbr_plugin.h
@@ -170,7 +170,7 @@ struct BR_EXPORT File @@ -170,7 +170,7 @@ struct BR_EXPORT File
170 { 170 {
171 QString name; /*!< \brief Path to a file on disk. */ 171 QString name; /*!< \brief Path to a file on disk. */
172 172
173 - File() {} 173 + File() { fte = false; }
174 File(const QString &file) { init(file); } /*!< \brief Construct a file from a string. */ 174 File(const QString &file) { init(file); } /*!< \brief Construct a file from a string. */
175 File(const QString &file, const QVariant &label) { init(file); set("Label", label); } /*!< \brief Construct a file from a string and assign a label. */ 175 File(const QString &file, const QVariant &label) { init(file); set("Label", label); } /*!< \brief Construct a file from a string and assign a label. */
176 File(const char *file) { init(file); } /*!< \brief Construct a file from a c-style string. */ 176 File(const char *file) { init(file); } /*!< \brief Construct a file from a c-style string. */
@@ -308,7 +308,7 @@ struct BR_EXPORT File @@ -308,7 +308,7 @@ struct BR_EXPORT File
308 return result; 308 return result;
309 } 309 }
310 310
311 - inline bool failed() const { return getBool("FTE") || getBool("FTO"); } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */ 311 + inline bool failed() const { return fte; } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */
312 312
313 QList<QPointF> namedPoints() const; /*!< \brief Returns points convertible from metadata keys. */ 313 QList<QPointF> namedPoints() const; /*!< \brief Returns points convertible from metadata keys. */
314 QList<QPointF> points() const; /*!< \brief Returns the file's points list. */ 314 QList<QPointF> points() const; /*!< \brief Returns the file's points list. */
@@ -327,6 +327,7 @@ struct BR_EXPORT File @@ -327,6 +327,7 @@ struct BR_EXPORT File
327 inline void setRects(const QList<QRectF> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */ 327 inline void setRects(const QList<QRectF> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */
328 inline void setRects(const QList<cv::Rect> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */ 328 inline void setRects(const QList<cv::Rect> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */
329 329
  330 + bool fte;
330 private: 331 private:
331 QVariantMap m_metadata; 332 QVariantMap m_metadata;
332 BR_EXPORT friend QDataStream &operator<<(QDataStream &stream, const File &file); 333 BR_EXPORT friend QDataStream &operator<<(QDataStream &stream, const File &file);
@@ -1295,7 +1296,7 @@ public: @@ -1295,7 +1296,7 @@ public:
1295 * \brief Return a pointer to a simplified version of this transform (if possible). Transforms which are only active during training should remove 1296 * \brief Return a pointer to a simplified version of this transform (if possible). Transforms which are only active during training should remove
1296 * themselves by either returning their child transforms (where relevant) or returning NULL. Set newTransform to true if the transform returned is newly allocated. 1297 * themselves by either returning their child transforms (where relevant) or returning NULL. Set newTransform to true if the transform returned is newly allocated.
1297 */ 1298 */
1298 - virtual Transform * simplify(bool & newTransform) { newTransform = false; return this; } 1299 + virtual Transform * simplify(bool &newTransform) { newTransform = false; return this; }
1299 1300
1300 protected: 1301 protected:
1301 Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */ 1302 Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */
openbr/plugins/draw.cpp
@@ -607,7 +607,7 @@ class MeanImageTransform : public TimeVaryingTransform @@ -607,7 +607,7 @@ class MeanImageTransform : public TimeVaryingTransform
607 cnt++; 607 cnt++;
608 } 608 }
609 609
610 - virtual void finalize(TemplateList & output) 610 + virtual void finalize(TemplateList &output)
611 { 611 {
612 average /= float(cnt); 612 average /= float(cnt);
613 imwrite(QString("%1.%2").arg(imgname).arg(ext).toStdString(), average); 613 imwrite(QString("%1.%2").arg(imgname).arg(ext).toStdString(), average);
openbr/plugins/keypoint.cpp
@@ -54,7 +54,7 @@ class KeyPointDetectorTransform : public UntrainableTransform @@ -54,7 +54,7 @@ class KeyPointDetectorTransform : public UntrainableTransform
54 featureDetector->detect(src, keyPoints); 54 featureDetector->detect(src, keyPoints);
55 } catch (...) { 55 } catch (...) {
56 qWarning("Key point detection failed for file %s", qPrintable(src.file.name)); 56 qWarning("Key point detection failed for file %s", qPrintable(src.file.name));
57 - dst.file.set("FTE", true); 57 + dst.file.fte = true;
58 } 58 }
59 59
60 QList<Rect> rects; 60 QList<Rect> rects;
openbr/plugins/meta.cpp
@@ -76,8 +76,21 @@ class PipeTransform : public CompositeTransform @@ -76,8 +76,21 @@ class PipeTransform : public CompositeTransform
76 76
77 void _projectPartial(TemplateList *srcdst, int startIndex, int stopIndex) 77 void _projectPartial(TemplateList *srcdst, int startIndex, int stopIndex)
78 { 78 {
79 - for (int i=startIndex; i<stopIndex; i++)  
80 - *srcdst >> *transforms[i]; 79 + TemplateList dst = *srcdst;
  80 + TemplateList temp;
  81 + for (int i=startIndex; i<stopIndex; i++) {
  82 + TemplateList temp;
  83 + transforms[i]->project(dst, temp);
  84 +
  85 + dst.clear();
  86 + foreach (const Template &t, *srcdst) {
  87 + if (!t.file.fte)
  88 + dst.append(t);
  89 + else
  90 + srcdst->append(t);
  91 + }
  92 + }
  93 + srcdst->append(dst);
81 } 94 }
82 95
83 void train(const QList<TemplateList> &data) 96 void train(const QList<TemplateList> &data)
@@ -136,10 +149,13 @@ class PipeTransform : public CompositeTransform @@ -136,10 +149,13 @@ class PipeTransform : public CompositeTransform
136 foreach (Transform *f, transforms) { 149 foreach (Transform *f, transforms) {
137 try { 150 try {
138 f->projectUpdate(dst); 151 f->projectUpdate(dst);
  152 + if (dst.file.fte)
  153 + break;
139 } catch (...) { 154 } catch (...) {
140 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); 155 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
141 dst = Template(src.file); 156 dst = Template(src.file);
142 - dst.file.set("FTE", true); 157 + dst.file.fte = true;
  158 + break;
143 } 159 }
144 } 160 }
145 } 161 }
@@ -149,8 +165,7 @@ class PipeTransform : public CompositeTransform @@ -149,8 +165,7 @@ class PipeTransform : public CompositeTransform
149 void projectUpdate(const TemplateList &src, TemplateList &dst) 165 void projectUpdate(const TemplateList &src, TemplateList &dst)
150 { 166 {
151 dst = src; 167 dst = src;
152 - foreach (Transform *f, transforms)  
153 - { 168 + foreach (Transform *f, transforms) {
154 f->projectUpdate(dst); 169 f->projectUpdate(dst);
155 } 170 }
156 } 171 }
@@ -188,9 +203,7 @@ class PipeTransform : public CompositeTransform @@ -188,9 +203,7 @@ class PipeTransform : public CompositeTransform
188 continue; 203 continue;
189 } 204 }
190 for (int j=0; j < probe->transforms.size(); j++) 205 for (int j=0; j < probe->transforms.size(); j++)
191 - {  
192 flattened.append(probe->transforms[j]); 206 flattened.append(probe->transforms[j]);
193 - }  
194 } 207 }
195 transforms = flattened; 208 transforms = flattened;
196 209
@@ -202,10 +215,20 @@ protected: @@ -202,10 +215,20 @@ protected:
202 // or if parallelism is disabled, handle them sequentially 215 // or if parallelism is disabled, handle them sequentially
203 void _project(const TemplateList &src, TemplateList &dst) const 216 void _project(const TemplateList &src, TemplateList &dst) const
204 { 217 {
205 - dst = src; 218 + TemplateList temp, output;
  219 + temp = src;
206 foreach (const Transform *f, transforms) { 220 foreach (const Transform *f, transforms) {
207 - dst >> *f; 221 + dst.clear();
  222 + f->project(temp, dst);
  223 + temp.clear();
  224 + foreach(const Template &t, dst) {
  225 + if (!t.file.fte)
  226 + temp.append(t);
  227 + else output.append(t);
  228 + }
208 } 229 }
  230 + output.append(temp);
  231 + dst = output;
209 } 232 }
210 233
211 // Single template const project, pass the template through each sub-transform, one after the other 234 // Single template const project, pass the template through each sub-transform, one after the other
@@ -215,10 +238,12 @@ protected: @@ -215,10 +238,12 @@ protected:
215 foreach (const Transform *f, transforms) { 238 foreach (const Transform *f, transforms) {
216 try { 239 try {
217 dst >> *f; 240 dst >> *f;
  241 + if (dst.file.fte)
  242 + break;
218 } catch (...) { 243 } catch (...) {
219 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); 244 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
220 dst = Template(src.file); 245 dst = Template(src.file);
221 - dst.file.set("FTE", true); 246 + dst.file.fte = true;
222 } 247 }
223 } 248 }
224 } 249 }
@@ -323,7 +348,8 @@ class ForkTransform : public CompositeTransform @@ -323,7 +348,8 @@ class ForkTransform : public CompositeTransform
323 } catch (...) { 348 } catch (...) {
324 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); 349 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
325 dst = Template(src.file); 350 dst = Template(src.file);
326 - dst.file.set("FTE", true); 351 + dst.file.fte = true;
  352 + break;
327 } 353 }
328 } 354 }
329 } 355 }
@@ -379,7 +405,8 @@ protected: @@ -379,7 +405,8 @@ protected:
379 } catch (...) { 405 } catch (...) {
380 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); 406 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
381 dst = Template(src.file); 407 dst = Template(src.file);
382 - dst.file.set("FTE", true); 408 + dst.file.fte = true;
  409 + break;
383 } 410 }
384 } 411 }
385 } 412 }
openbr/plugins/misc.cpp
@@ -52,7 +52,8 @@ class OpenTransform : public UntrainableMetaTransform @@ -52,7 +52,8 @@ class OpenTransform : public UntrainableMetaTransform
52 dst.append(t); 52 dst.append(t);
53 dst.file.append(t.file.localMetadata()); 53 dst.file.append(t.file.localMetadata());
54 } 54 }
55 - dst.file.set("FTO", dst.isEmpty()); 55 + if (dst.isEmpty())
  56 + dst.file.fte = true;
56 } else { 57 } else {
57 // Propogate or decode existing matricies 58 // Propogate or decode existing matricies
58 foreach (const Mat &m, src) { 59 foreach (const Mat &m, src) {
@@ -610,6 +611,10 @@ class GalleryOutputTransform : public TimeVaryingTransform @@ -610,6 +611,10 @@ class GalleryOutputTransform : public TimeVaryingTransform
610 if (src.empty()) 611 if (src.empty())
611 return; 612 return;
612 dst = src; 613 dst = src;
  614 + for (int i=0; i < dst.size();i++) {
  615 + if (dst[i].file.getBool("FTE"))
  616 + dst[i].file.fte = true;
  617 + }
613 writer->writeBlock(dst); 618 writer->writeBlock(dst);
614 } 619 }
615 620
@@ -725,8 +730,10 @@ class OutputTransform : public TimeVaryingTransform @@ -725,8 +730,10 @@ class OutputTransform : public TimeVaryingTransform
725 730
726 // we received a template, which is the next row/column in order 731 // we received a template, which is the next row/column in order
727 foreach (const Template &t, dst) { 732 foreach (const Template &t, dst) {
728 - for (int i=0; i < t.m().cols; i++) {  
729 - output->setRelative(t.m().at<float>(0, i), currentRow, currentCol); 733 + bool fte = t.file.getBool("FTE") || t.file.fte;
  734 +
  735 + for (int i=0; i < scoresPerMat; i++) {
  736 + output->setRelative(fte ? -std::numeric_limits<float>::max() : t.m().at<float>(0, i), currentRow, currentCol);
730 737
731 // row-major input 738 // row-major input
732 if (!transposeMode) 739 if (!transposeMode)
@@ -794,10 +801,12 @@ class OutputTransform : public TimeVaryingTransform @@ -794,10 +801,12 @@ class OutputTransform : public TimeVaryingTransform
794 fragmentsPerRow = bufferedSize; 801 fragmentsPerRow = bufferedSize;
795 // a single col contains comparisons to all query files 802 // a single col contains comparisons to all query files
796 fragmentsPerCol = queryFiles.size(); 803 fragmentsPerCol = queryFiles.size();
  804 + scoresPerMat = fragmentsPerCol;
797 } 805 }
798 else { 806 else {
799 // a single row contains comparisons to all target files 807 // a single row contains comparisons to all target files
800 fragmentsPerRow = targetFiles.size(); 808 fragmentsPerRow = targetFiles.size();
  809 + scoresPerMat = fragmentsPerRow;
801 // we output rows one at a time 810 // we output rows one at a time
802 fragmentsPerCol = 1; 811 fragmentsPerCol = 1;
803 } 812 }
@@ -823,6 +832,8 @@ class OutputTransform : public TimeVaryingTransform @@ -823,6 +832,8 @@ class OutputTransform : public TimeVaryingTransform
823 int fragmentsPerRow; 832 int fragmentsPerRow;
824 int fragmentsPerCol; 833 int fragmentsPerCol;
825 834
  835 + int scoresPerMat;
  836 +
826 public: 837 public:
827 OutputTransform() : TimeVaryingTransform(false,false) {} 838 OutputTransform() : TimeVaryingTransform(false,false) {}
828 }; 839 };
openbr/plugins/pp5.cpp
@@ -323,7 +323,7 @@ class PP5EnrollTransform : public UntrainableMetaTransform @@ -323,7 +323,7 @@ class PP5EnrollTransform : public UntrainableMetaTransform
323 // No faces were detected when we were expecting one, output something with FTE set. 323 // No faces were detected when we were expecting one, output something with FTE set.
324 if (!foundFace && !Globals->enrollAll) { 324 if (!foundFace && !Globals->enrollAll) {
325 dstList.append(Template(src.file, detectOnly ? src.m() : cv::Mat())); 325 dstList.append(Template(src.file, detectOnly ? src.m() : cv::Mat()));
326 - dstList.last().file.set("FTE", true); 326 + dstList.last().file.fte = true;
327 } 327 }
328 } 328 }
329 329
openbr/plugins/stasm4.cpp
@@ -144,7 +144,7 @@ class StasmTransform : public UntrainableTransform @@ -144,7 +144,7 @@ class StasmTransform : public UntrainableTransform
144 144
145 if (!foundFace) { 145 if (!foundFace) {
146 if (Globals->verbose) qWarning("No face found in %s.", qPrintable(src.file.fileName())); 146 if (Globals->verbose) qWarning("No face found in %s.", qPrintable(src.file.fileName()));
147 - dst.file.set("FTE",true); 147 + dst.file.fte = true;
148 } else { 148 } else {
149 QList<QPointF> points; 149 QList<QPointF> points;
150 for (int i = 0; i < nLandmarks; i++) { 150 for (int i = 0; i < nLandmarks; i++) {
openbr/plugins/stream.cpp
@@ -907,7 +907,17 @@ public: @@ -907,7 +907,17 @@ public:
907 qFatal("null input to multi-thread stage"); 907 qFatal("null input to multi-thread stage");
908 } 908 }
909 909
910 - input->data >> *transform; 910 + TemplateList project;
  911 + TemplateList completed;
  912 + for (int i=0; i < input->data.size(); i++) {
  913 + if (input->data[i].file.fte)
  914 + completed.append(input->data[i]);
  915 + else
  916 + project.append(input->data[i]);
  917 + }
  918 + input->data.clear();
  919 + transform->project(project, input->data);
  920 + input->data.append(completed);
911 921
912 should_continue = nextStage->tryAcquireNextStage(input, final); 922 should_continue = nextStage->tryAcquireNextStage(input, final);
913 923
@@ -927,7 +937,7 @@ public: @@ -927,7 +937,7 @@ public:
927 { 937 {
928 // nothing to do. 938 // nothing to do.
929 } 939 }
930 - void status(){ 940 + void status() {
931 qDebug("multi thread stage %d, nothing to worry about", this->stage_id); 941 qDebug("multi thread stage %d, nothing to worry about", this->stage_id);
932 } 942 }
933 }; 943 };
@@ -980,13 +990,22 @@ public: @@ -980,13 +990,22 @@ public:
980 qFatal("NULL input to stage %d", this->stage_id); 990 qFatal("NULL input to stage %d", this->stage_id);
981 991
982 if (input->sequenceNumber != next_target) 992 if (input->sequenceNumber != next_target)
983 - {  
984 qFatal("out of order frames for stage %d, got %d expected %d", this->stage_id, input->sequenceNumber, this->next_target); 993 qFatal("out of order frames for stage %d, got %d expected %d", this->stage_id, input->sequenceNumber, this->next_target);
985 - } 994 +
986 next_target = input->sequenceNumber + 1; 995 next_target = input->sequenceNumber + 1;
987 996
  997 + TemplateList project;
  998 + TemplateList completed;
  999 + foreach (const Template &t, input->data) {
  1000 + if (t.file.fte)
  1001 + completed.append(t);
  1002 + else
  1003 + project.append(t);
  1004 + }
  1005 + input->data.clear();
988 // Project the input we got 1006 // Project the input we got
989 - transform->projectUpdate(input->data); 1007 + transform->projectUpdate(project, input->data);
  1008 + input->data.append(completed);
990 1009
991 should_continue = nextStage->tryAcquireNextStage(input,final); 1010 should_continue = nextStage->tryAcquireNextStage(input,final);
992 1011
@@ -1057,12 +1076,40 @@ public: @@ -1057,12 +1076,40 @@ public:
1057 return true; 1076 return true;
1058 } 1077 }
1059 1078
1060 - void status(){ 1079 + void status() {
1061 qDebug("single thread stage %d, status starting? %d, next %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->inputBuffer->size()); 1080 qDebug("single thread stage %d, status starting? %d, next %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->inputBuffer->size());
1062 } 1081 }
1063 1082
1064 }; 1083 };
1065 1084
  1085 +class EndStage : public SingleThreadStage
  1086 +{
  1087 +public:
  1088 + EndStage(bool input_variance) : SingleThreadStage(input_variance) {}
  1089 +
  1090 + ~EndStage() {}
  1091 +
  1092 + // Calledfrom a different thread than run.
  1093 + bool tryAcquireNextStage(FrameData *& input, bool &final)
  1094 + {
  1095 + for (int i=0; i < input->data.size(); i++) {
  1096 + if (input->data[i].file.fte) {
  1097 + input->data[i].file.fte = false;
  1098 + input->data[i].file.set("FTE",QVariant::fromValue(true));
  1099 + }
  1100 + else
  1101 + input->data[i].file.set("FTE",QVariant::fromValue(false));
  1102 + }
  1103 +
  1104 + return SingleThreadStage::tryAcquireNextStage(input, final);
  1105 + }
  1106 +
  1107 + void status() {
  1108 + qDebug("end stage %d, status starting? %d, next %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->inputBuffer->size());
  1109 + }
  1110 +
  1111 +};
  1112 +
1066 // Semi-functional, doesn't do anything productive outside of stream::train 1113 // Semi-functional, doesn't do anything productive outside of stream::train
1067 class CollectSets : public TimeVaryingTransform 1114 class CollectSets : public TimeVaryingTransform
1068 { 1115 {
@@ -1099,7 +1146,7 @@ public: @@ -1099,7 +1146,7 @@ public:
1099 data.append(src); 1146 data.append(src);
1100 } 1147 }
1101 1148
1102 - void finalize(TemplateList & output) 1149 + void finalize(TemplateList &output)
1103 { 1150 {
1104 output = data; 1151 output = data;
1105 data.clear(); 1152 data.clear();
@@ -1198,7 +1245,7 @@ public: @@ -1198,7 +1245,7 @@ public:
1198 return true; 1245 return true;
1199 } 1246 }
1200 1247
1201 - void status(){ 1248 + void status() {
1202 qDebug("Read stage %d, status starting? %d, next frame %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->dataSource.size()); 1249 qDebug("Read stage %d, status starting? %d, next frame %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->dataSource.size());
1203 } 1250 }
1204 }; 1251 };
@@ -1463,7 +1510,7 @@ public: @@ -1463,7 +1510,7 @@ public:
1463 1510
1464 // We also have the last stage, which just puts the output of the 1511 // We also have the last stage, which just puts the output of the
1465 // previous stages on a template list. 1512 // previous stages on a template list.
1466 - collectionStage = new SingleThreadStage(prev_stage_variance); 1513 + collectionStage = new EndStage(prev_stage_variance);
1467 collectionStage->transform = this->endPoint; 1514 collectionStage->transform = this->endPoint;
1468 1515
1469 1516