mirror of
https://github.com/TomHarte/CLK.git
synced 2026-03-12 10:42:14 +00:00
Detect and expose is-interlaced flag.
With plenty of exposition to avoid confusing the reader into thinking that the emulator is predicated on this in an unrealistic fashion.
This commit is contained in:
@@ -234,6 +234,29 @@ void BufferingScanTarget::announce(
|
||||
++read;
|
||||
frame_read_.store(read, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// Look for an even-odd pattern in start-of-frame line placement as an indication that
|
||||
// incoming video is interlaced. That might be helpful information in deciding exactly
|
||||
// how to display scans pleasantly, depending on the display target.
|
||||
start_history_[start_history_pointer_] = location;
|
||||
++start_history_pointer_;
|
||||
|
||||
static constexpr int CoordinateEpsilon = 100;
|
||||
const auto similar_enough = [&](const size_t start, const size_t stride) {
|
||||
for(size_t index = start + stride; index < start_history_.size(); index += stride) {
|
||||
if(
|
||||
abs(start_history_[index - stride].x - start_history_[index].x) > CoordinateEpsilon ||
|
||||
abs(start_history_[index - stride].y - start_history_[index].y) > CoordinateEpsilon
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
is_interlaced_.store(
|
||||
!similar_enough(0, 1) && similar_enough(0, 2) && similar_enough(1, 2),
|
||||
std::memory_order_relaxed
|
||||
);
|
||||
}
|
||||
|
||||
// Proceed from here only if a change in visibility has occurred.
|
||||
@@ -416,3 +439,7 @@ const Outputs::Display::ScanTarget::Modals &BufferingScanTarget::modals() const
|
||||
bool BufferingScanTarget::has_new_modals() const {
|
||||
return modals_are_dirty_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool BufferingScanTarget::is_interlaced() const {
|
||||
return is_interlaced_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@@ -164,6 +164,13 @@ public:
|
||||
/// @returns the current @c Modals.
|
||||
const Modals &modals() const;
|
||||
|
||||
/// @returns whether the current output being received appears to describe an interlaced signal.
|
||||
/// This is a hint only, potentially to provide for better deinterlacing of output, being derived locally
|
||||
/// from line positioning. Specifically: if a scan target pays no heed to this whatsoever it's likely to
|
||||
/// end up doing the equivalent of a bob. If it so desires, it might prefer to do something closer to
|
||||
/// a weave if and only if interlaced video is detected.
|
||||
bool is_interlaced() const;
|
||||
|
||||
/// @returns @c true if new modals are available; @c false otherwise.
|
||||
///
|
||||
/// Safe to call from any thread.
|
||||
@@ -317,6 +324,12 @@ private:
|
||||
std::atomic<Numeric::CircularCounter<uint16_t, NumFrames>> frame_read_;
|
||||
std::atomic<Numeric::CircularCounter<uint16_t, NumFrames>> frame_write_;
|
||||
|
||||
// A recent history of field start positions, to allow detection of interlaced video.
|
||||
// That can be used as a hint for display purposes.
|
||||
static constexpr size_t StartHistoryLength = 16;
|
||||
std::array<Outputs::Display::ScanTarget::Scan::EndPoint, StartHistoryLength> start_history_;
|
||||
Numeric::CircularCounter<size_t, StartHistoryLength> start_history_pointer_;
|
||||
std::atomic<bool> is_interlaced_ = false;
|
||||
|
||||
// By convention everything in the PointerSet points to the next instance
|
||||
// of whatever it is that will be used. So a client should start with whatever
|
||||
|
||||
Reference in New Issue
Block a user