diff --git a/src/async_video_provider.cpp b/src/async_video_provider.cpp index 8a0a2dfd1..ba9cbe287 100644 --- a/src/async_video_provider.cpp +++ b/src/async_video_provider.cpp @@ -140,10 +140,53 @@ void AsyncVideoProvider::RequestFrame(int new_frame, double new_time) throw() { }); } +bool AsyncVideoProvider::NeedUpdate(std::vector const& visible_lines) { + // Always need to render after a seek + if (single_frame != NEW_SUBS_FILE || frame_number != last_rendered) + return true; + + // Obviously need to render if the number of visible lines has changed + if (visible_lines.size() != last_lines.size()) + return true; + + for (size_t i = 0; i < last_lines.size(); ++i) { + auto const& last = last_lines[i]; + auto const& cur = *visible_lines[i]; + if (last.Layer != cur.Layer) return true; + if (last.Margin != cur.Margin) return true; + if (last.Style != cur.Style) return true; + if (last.Effect != cur.Effect) return true; + if (last.Text != cur.Text) return true; + + // Changing the start/end time effects the appearance only if the + // line is animated. This is obviously not a very accurate check for + // animated lines, but false positives aren't the end of the world + if ((last.Start != cur.Start || last.End != cur.End) && + (!cur.Effect.get().empty() || cur.Text.get().find('\\') != std::string::npos)) + return true; + } + + return false; +} + void AsyncVideoProvider::ProcAsync(uint_fast32_t req_version) { // Only actually produce the frame if there's no queued changes waiting if (req_version < version || frame_number < 0) return; + std::vector visible_lines; + for (auto const& line : subs->Events) { + if (!line.Comment && !(line.Start > time || line.End <= time)) + visible_lines.push_back(&line); + } + + if (!NeedUpdate(visible_lines)) return; + + last_lines.clear(); + last_lines.reserve(visible_lines.size()); + for (auto line : visible_lines) + last_lines.push_back(*line); + last_rendered = frame_number; + try { FrameReadyEvent *evt = new FrameReadyEvent(ProcFrame(frame_number, time), time); evt->SetEventType(EVT_FRAME_READY); diff --git a/src/async_video_provider.h b/src/async_video_provider.h index 37232b978..c77a2664c 100644 --- a/src/async_video_provider.h +++ b/src/async_video_provider.h @@ -29,6 +29,7 @@ class AssFile; class SubtitlesProvider; class VideoProvider; class VideoProviderError; +struct AssDialogueBase; struct VideoFrame; namespace agi { class BackgroundRunner; @@ -58,6 +59,14 @@ class AsyncVideoProvider { /// currently loaded file is out of date. int single_frame = -1; + /// Last rendered frame number + int last_rendered = -1; + /// Last rendered subtitles on that frame + std::vector last_lines; + /// Check if we actually need to honor a frame request or if no visible + /// lines have actually changed + bool NeedUpdate(std::vector const& visible_lines); + std::shared_ptr ProcFrame(int frame, double time, bool raw = false); /// Produce a frame if req_version is still the current version