Loading debian/changelog +8 −0 Original line number Diff line number Diff line mediadb (20260419+26) unstable; urgency=critical * Fix preview std::future_error exception caused by invalidating future read states. Store resolved data locally within the asynchronous `PendingBlock` struct to avoid reading from an expired future multiple times on fragmented FFmpeg chunk reads. -- Jan Koester <jan.koester@tuxist.de> Sun, 19 Apr 2026 15:00:00 +0200 mediadb (20260419+25) unstable; urgency=critical * Fix preview render queue lock-up where an exception thrown during Loading src/preview.cpp +12 −7 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ struct PrefetchBuffer { std::uint64_t offset; std::uint64_t length; std::future<std::vector<uint8_t>> fut; std::vector<uint8_t> data; }; std::deque<PendingBlock> ring; Loading Loading @@ -75,8 +76,8 @@ struct PrefetchBuffer { auto cached = cache_get(off, len); if (!cached.empty()) { std::promise<std::vector<uint8_t>> p; p.set_value(std::move(cached)); ring.push_back(PendingBlock{off, len, p.get_future()}); p.set_value(cached); ring.push_back(PendingBlock{off, len, p.get_future(), std::vector<uint8_t>()}); } else { ring.push_back(PendingBlock{ off, len, Loading @@ -84,7 +85,8 @@ struct PrefetchBuffer { auto bytes = db->read_media_data_range(media_id, off, len); cache_put(off, len, bytes); return bytes; }) }), std::vector<uint8_t>() }); } next += len; Loading Loading @@ -114,16 +116,19 @@ struct PrefetchBuffer { } auto& front = ring.front(); auto data = front.fut.get(); if (data.empty()) { if (front.data.empty() && front.fut.valid()) { front.data = front.fut.get(); } if (front.data.empty()) { ring.pop_front(); return AVERROR_EOF; } std::uint64_t offset_in_block = pos - front.offset; std::uint64_t avail = data.size() - offset_in_block; std::uint64_t avail = front.data.size() - offset_in_block; std::uint64_t n = std::min<std::uint64_t>(want, avail); std::memcpy(buf, data.data() + offset_in_block, n); std::memcpy(buf, front.data.data() + offset_in_block, n); pos += n; if (pos >= front.offset + front.length) { Loading Loading
debian/changelog +8 −0 Original line number Diff line number Diff line mediadb (20260419+26) unstable; urgency=critical * Fix preview std::future_error exception caused by invalidating future read states. Store resolved data locally within the asynchronous `PendingBlock` struct to avoid reading from an expired future multiple times on fragmented FFmpeg chunk reads. -- Jan Koester <jan.koester@tuxist.de> Sun, 19 Apr 2026 15:00:00 +0200 mediadb (20260419+25) unstable; urgency=critical * Fix preview render queue lock-up where an exception thrown during Loading
src/preview.cpp +12 −7 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ struct PrefetchBuffer { std::uint64_t offset; std::uint64_t length; std::future<std::vector<uint8_t>> fut; std::vector<uint8_t> data; }; std::deque<PendingBlock> ring; Loading Loading @@ -75,8 +76,8 @@ struct PrefetchBuffer { auto cached = cache_get(off, len); if (!cached.empty()) { std::promise<std::vector<uint8_t>> p; p.set_value(std::move(cached)); ring.push_back(PendingBlock{off, len, p.get_future()}); p.set_value(cached); ring.push_back(PendingBlock{off, len, p.get_future(), std::vector<uint8_t>()}); } else { ring.push_back(PendingBlock{ off, len, Loading @@ -84,7 +85,8 @@ struct PrefetchBuffer { auto bytes = db->read_media_data_range(media_id, off, len); cache_put(off, len, bytes); return bytes; }) }), std::vector<uint8_t>() }); } next += len; Loading Loading @@ -114,16 +116,19 @@ struct PrefetchBuffer { } auto& front = ring.front(); auto data = front.fut.get(); if (data.empty()) { if (front.data.empty() && front.fut.valid()) { front.data = front.fut.get(); } if (front.data.empty()) { ring.pop_front(); return AVERROR_EOF; } std::uint64_t offset_in_block = pos - front.offset; std::uint64_t avail = data.size() - offset_in_block; std::uint64_t avail = front.data.size() - offset_in_block; std::uint64_t n = std::min<std::uint64_t>(want, avail); std::memcpy(buf, data.data() + offset_in_block, n); std::memcpy(buf, front.data.data() + offset_in_block, n); pos += n; if (pos >= front.offset + front.length) { Loading