From d585ac503adef85a155ab7bc0e8ef0172d226efe Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Sat, 17 Oct 2020 11:31:08 +0300
Subject: [PATCH] Fix loading of static FTL files

---
 components/codecs/src/opencv_decoder.cpp | 26 ++++++------
 components/streams/src/filestream.cpp    | 53 +++++++++++++++++++++---
 2 files changed, 61 insertions(+), 18 deletions(-)

diff --git a/components/codecs/src/opencv_decoder.cpp b/components/codecs/src/opencv_decoder.cpp
index f4b3c0a20..b7f1a600f 100644
--- a/components/codecs/src/opencv_decoder.cpp
+++ b/components/codecs/src/opencv_decoder.cpp
@@ -20,7 +20,7 @@ bool OpenCVDecoder::accepts(const ftl::codecs::Packet &pkt) {
 }
 
 bool OpenCVDecoder::decode(const ftl::codecs::Packet &pkt, cv::cuda::GpuMat &out) { 
-	int chunk_dim = 1; //std::sqrt(pkt.frame_count);
+	/*int chunk_dim = 1; //std::sqrt(pkt.frame_count);
 	int chunk_width = out.cols / chunk_dim;
 	int chunk_height = out.rows / chunk_dim;
 
@@ -28,7 +28,7 @@ bool OpenCVDecoder::decode(const ftl::codecs::Packet &pkt, cv::cuda::GpuMat &out
 	int cx = 0; //(pkt.block_number % chunk_dim) * chunk_width;
 	int cy = 0; //(pkt.block_number / chunk_dim) * chunk_height;
 	cv::Rect roi(cx,cy,chunk_width,chunk_height);
-	cv::cuda::GpuMat chunkHead = out(roi);
+	cv::cuda::GpuMat chunkHead = out(roi);*/
 
 	cv::Mat tmp2_, tmp_;
 	// Decode in temporary buffers to prevent long locks
@@ -47,22 +47,22 @@ bool OpenCVDecoder::decode(const ftl::codecs::Packet &pkt, cv::cuda::GpuMat &out
 	// Can either check JPG/PNG headers or just use pkt definition.
 
 	// Original size so just copy
-	if (tmp_.cols == chunkHead.cols) {
-		if (!tmp_.empty() && tmp_.type() == CV_16U && chunkHead.type() == CV_32F) {
+	//if (tmp_.cols == chunkHead.cols) {
+		if (!tmp_.empty() && tmp_.type() == CV_16U) {
 			tmp_.convertTo(tmp_, CV_32FC1, 1.0f/1000.0f);
-			chunkHead.upload(tmp_);
-		} else if (!tmp_.empty() && tmp_.type() == CV_8UC4 && chunkHead.type() == CV_8UC4) {
+			out.upload(tmp_);
+		} else if (!tmp_.empty() && tmp_.type() == CV_8UC4) {
 			//tmp_.copyTo(chunkHead);
-			chunkHead.upload(tmp_);
-		} else if (!tmp_.empty() && tmp_.type() == CV_16U && chunkHead.type() == CV_16U) {
-			chunkHead.upload(tmp_);
-		} else if (!tmp_.empty() && tmp_.type() == CV_8UC1 && chunkHead.type() == CV_8UC1) {
-			chunkHead.upload(tmp_);
+			out.upload(tmp_);
+		} else if (!tmp_.empty() && tmp_.type() == CV_16U) {
+			out.upload(tmp_);
+		} else if (!tmp_.empty() && tmp_.type() == CV_8UC1) {
+			out.upload(tmp_);
 		} else {
 			// Silent ignore?
 		}
 	// Downsized so needs a scale up
-	} else {
+	/*} else {
 		if (!tmp_.empty() && tmp_.type() == CV_16U && chunkHead.type() == CV_32F) {
 			tmp_.convertTo(tmp_, CV_32FC1, 1.0f/1000.0f); //(16.0f*10.0f));
 			cv::resize(tmp_, tmp_, chunkHead.size(), 0, 0, cv::INTER_NEAREST);
@@ -73,7 +73,7 @@ bool OpenCVDecoder::decode(const ftl::codecs::Packet &pkt, cv::cuda::GpuMat &out
 		} else {
 			// Silent ignore?
 		}
-	}
+	}*/
 
 	return true;
 }
diff --git a/components/streams/src/filestream.cpp b/components/streams/src/filestream.cpp
index 0044d0142..96159a544 100644
--- a/components/streams/src/filestream.cpp
+++ b/components/streams/src/filestream.cpp
@@ -94,7 +94,10 @@ bool File::_checkFile() {
 	is_video_ = count < 9;
 
 	LOG(INFO) << " -- Frame rate = " << (1000 / min_ts_diff);
-	if (!is_video_) LOG(INFO) << " -- Static image";
+	if (!is_video_) {
+		LOG(INFO) << " -- Static image";
+		set("looping", false);
+	}
 
 	std::string codec_str = "";
 	for (auto c : codecs_found) {
@@ -327,6 +330,8 @@ bool File::tick(int64_t ts) {
 					spkt.flags = 0;
 					spkt.channel = Channel::EndFrame;
 
+					//LOG(INFO) << "Send EndFrame: " << spkt.timestamp << ", " << int(spkt.streamID);
+
 					Packet pkt;
 					pkt.bitrate = 255;
 					pkt.codec = ftl::codecs::codec_t::Invalid;
@@ -355,8 +360,8 @@ bool File::tick(int64_t ts) {
 		}
 	}
 
-	int64_t max_ts = 0;
-	for (auto &fsd : framesets_) max_ts = std::max(max_ts, (fsd.second.timestamp == 0) ? timestart_ : fsd.second.timestamp);
+	int64_t max_ts = std::numeric_limits<int64_t>::min();
+	for (auto &fsd : framesets_) max_ts = std::max(max_ts, (fsd.second.timestamp <= 0) ? timestart_ : fsd.second.timestamp);
 	int64_t extended_ts = max_ts + 200;  // Buffer 200ms ahead
 
 	while ((active_ && istream_->good()) || buffer_in_.nonparsed_size() > 0u) {
@@ -373,7 +378,7 @@ bool File::tick(int64_t ts) {
 
 		auto &fsdata = framesets_[std::get<0>(data).streamID];
 
-		if (fsdata.first_ts < 0) LOG(WARNING) << "Bad first timestamp";
+		if (fsdata.first_ts < 0) LOG(WARNING) << "Bad first timestamp " << fsdata.first_ts << ", " << std::get<0>(data).timestamp;
 
 		// Adjust timestamp
 		// FIXME: A potential bug where multiple times are merged into one?
@@ -386,7 +391,7 @@ bool File::tick(int64_t ts) {
 		// This should only occur for first few frames, generally otherwise
 		// the data buffer is already several frames ahead so is processed
 		// above. Hence, no need to bother parallelising this bit.
-		/*if (std::get<0>(data).timestamp <= timestamp_) {
+		/*if (!is_video_ && std::get<0>(data).timestamp <= timestamp_) {
 			std::get<0>(data).timestamp = ts;
 			//if (cb_) {
 				dlk.lock();
@@ -413,6 +418,44 @@ bool File::tick(int64_t ts) {
 	//	for (auto &fsd : framesets_) fsd.second.timestamp += interval_;
 	//}
 
+	// Force send end frames for static files
+	if (data_.size() == 0 && !is_video_) {
+		for (auto &fsix : framesets_) {
+			auto &fsdata = fsix.second;
+			if (fsdata.needs_endframe) {
+				fsdata.needs_endframe = false;
+				// Send final frame packet.
+				StreamPacket spkt;
+				spkt.timestamp = fsdata.timestamp;
+				spkt.streamID = fsix.first;
+				spkt.flags = 0;
+				spkt.channel = Channel::EndFrame;
+
+				//LOG(INFO) << "Send EndFrame: " << spkt.timestamp << ", " << int(spkt.streamID);
+
+				Packet pkt;
+				pkt.bitrate = 255;
+				pkt.codec = ftl::codecs::codec_t::Invalid;
+				pkt.packet_count = 1;
+				pkt.frame_count = 1;
+
+				for (size_t i=0; i<fsdata.frame_count; ++i) {
+					spkt.frame_number = i;
+					pkt.packet_count = fsdata.packet_counts[i]+1;
+					fsdata.packet_counts[i] = 0;
+
+					try {
+						cb_.trigger(spkt, pkt);
+					} catch (const ftl::exception &e) {
+						LOG(ERROR) << "Exception in packet callback: " << e.what() << e.trace();
+					} catch (std::exception &e) {
+						LOG(ERROR) << "Exception in packet callback: " << e.what();
+					}
+				}
+			}
+		}
+	}
+
 	if (data_.size() == 0 && value("looping", true)) {
 		buffer_in_.reset();
 		buffer_in_.remove_nonparsed_buffer();
-- 
GitLab