Avoid making a full copy of the file for ThreadedFrameSource when possible
When the set of changed lines is populated, only copy those lines rather than the entire file. On large files, this makes amend commits roughly twice as fast when video is open.
This commit is contained in:
parent
fee60be5db
commit
229e5d98c5
4 changed files with 60 additions and 13 deletions
|
@ -123,6 +123,7 @@ void *ThreadedFrameSource::Entry() {
|
|||
double time;
|
||||
int frameNum;
|
||||
std::unique_ptr<AssFile> newSubs;
|
||||
std::deque<std::pair<size_t, std::unique_ptr<AssEntry>>> updates;
|
||||
{
|
||||
wxMutexLocker jobLocker(jobMutex);
|
||||
|
||||
|
@ -138,11 +139,27 @@ void *ThreadedFrameSource::Entry() {
|
|||
frameNum = nextFrame;
|
||||
nextTime = -1.;
|
||||
newSubs = move(nextSubs);
|
||||
updates = move(changedSubs);
|
||||
}
|
||||
|
||||
if (newSubs) {
|
||||
if (newSubs || updates.size()) {
|
||||
wxMutexLocker fileLocker(fileMutex);
|
||||
subs = move(newSubs);
|
||||
|
||||
if (newSubs)
|
||||
subs = move(newSubs);
|
||||
|
||||
if (updates.size()) {
|
||||
size_t i = 0;
|
||||
auto it = subs->Line.begin();
|
||||
// Replace each changed line in subs with the updated version
|
||||
for (auto& update : updates) {
|
||||
advance(it, update.first - i);
|
||||
i = update.first;
|
||||
subs->Line.insert(it, *update.second.release());
|
||||
delete &*it--;
|
||||
}
|
||||
}
|
||||
|
||||
singleFrame = -1;
|
||||
}
|
||||
|
||||
|
@ -194,13 +211,27 @@ ThreadedFrameSource::~ThreadedFrameSource() {
|
|||
Wait();
|
||||
}
|
||||
|
||||
void ThreadedFrameSource::LoadSubtitles(AssFile *subs) throw() {
|
||||
subs = new AssFile(*subs);
|
||||
void ThreadedFrameSource::LoadSubtitles(const AssFile *subs) throw() {
|
||||
AssFile *copy = new AssFile(*subs);
|
||||
wxMutexLocker locker(jobMutex);
|
||||
// Set nextSubs and let the worker thread move it to subs so that we don't
|
||||
// have to lock fileMutex on the GUI thread, as that can be locked for
|
||||
// extended periods of time with slow-rendering subtitles
|
||||
nextSubs.reset(subs);
|
||||
nextSubs.reset(copy);
|
||||
changedSubs.clear();
|
||||
}
|
||||
|
||||
void ThreadedFrameSource::UpdateSubtitles(const AssFile *subs, std::set<const AssEntry*> changes) throw() {
|
||||
std::deque<std::pair<size_t, std::unique_ptr<AssEntry>>> changed;
|
||||
size_t i = 0;
|
||||
for (auto const& e : subs->Line) {
|
||||
if (changes.count(&e))
|
||||
changed.emplace_back(i, std::unique_ptr<AssEntry>(e.Clone()));
|
||||
++i;
|
||||
}
|
||||
|
||||
wxMutexLocker locker(jobMutex);
|
||||
changedSubs = std::move(changed);
|
||||
}
|
||||
|
||||
void ThreadedFrameSource::RequestFrame(int frame, double time) throw() {
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
/// @ingroup video
|
||||
///
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/thread.h>
|
||||
|
@ -28,6 +30,7 @@
|
|||
#include <libaegisub/scoped_ptr.h>
|
||||
|
||||
class AegiVideoFrame;
|
||||
class AssEntry;
|
||||
class AssFile;
|
||||
class SubtitlesProvider;
|
||||
class VideoProvider;
|
||||
|
@ -46,6 +49,7 @@ class ThreadedFrameSource : public wxThread {
|
|||
int nextFrame; ///< Next queued frame, or -1 for none
|
||||
double nextTime; ///< Next queued time
|
||||
std::unique_ptr<AssFile> nextSubs; ///< Next queued AssFile
|
||||
std::deque<std::pair<size_t, std::unique_ptr<AssEntry>>> changedSubs;
|
||||
|
||||
/// Subtitles to be loaded the next time a frame is requested
|
||||
std::unique_ptr<AssFile> subs;
|
||||
|
@ -70,7 +74,15 @@ public:
|
|||
///
|
||||
/// This function blocks until is it is safe for the calling thread to
|
||||
/// modify subs
|
||||
void LoadSubtitles(AssFile *subs) throw();
|
||||
void LoadSubtitles(const AssFile *subs) throw();
|
||||
|
||||
/// @brief Update a previously loaded subtitle file
|
||||
/// @param subs Subtitle file which was last passed to LoadSubtitles
|
||||
/// @param changes Set of lines which have changed
|
||||
///
|
||||
/// This function only supports changes to existing lines, and not
|
||||
/// insertions or deletions.
|
||||
void UpdateSubtitles(const AssFile *subs, std::set<const AssEntry *> changes) throw();
|
||||
|
||||
/// @brief Queue a request for a frame
|
||||
/// @brief frame Frame number
|
||||
|
|
|
@ -233,10 +233,13 @@ void VideoContext::Reload() {
|
|||
}
|
||||
}
|
||||
|
||||
void VideoContext::OnSubtitlesCommit() {
|
||||
void VideoContext::OnSubtitlesCommit(int type, std::set<const AssEntry *> const& changed) {
|
||||
if (!IsLoaded()) return;
|
||||
|
||||
provider->LoadSubtitles(context->ass);
|
||||
if (changed.empty())
|
||||
provider->LoadSubtitles(context->ass);
|
||||
else
|
||||
provider->UpdateSubtitles(context->ass, changed);
|
||||
if (!IsPlaying())
|
||||
GetFrameAsync(frame_n);
|
||||
}
|
||||
|
@ -446,7 +449,7 @@ void VideoContext::LoadTimecodes(wxString filename) {
|
|||
ovrFPS = agi::vfr::Framerate(STD_STR(filename));
|
||||
ovrTimecodeFile = filename;
|
||||
config::mru->Add("Timecodes", STD_STR(filename));
|
||||
OnSubtitlesCommit();
|
||||
OnSubtitlesCommit(0, std::set<const AssEntry*>());
|
||||
TimecodesOpen(ovrFPS);
|
||||
}
|
||||
catch (const agi::FileSystemError&) {
|
||||
|
@ -469,7 +472,7 @@ void VideoContext::SaveTimecodes(wxString filename) {
|
|||
void VideoContext::CloseTimecodes() {
|
||||
ovrFPS = agi::vfr::Framerate();
|
||||
ovrTimecodeFile.clear();
|
||||
OnSubtitlesCommit();
|
||||
OnSubtitlesCommit(0, std::set<const AssEntry*>());
|
||||
TimecodesOpen(videoFPS);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,10 @@
|
|||
/// @ingroup video
|
||||
///
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <wx/timer.h>
|
||||
#include <wx/stopwatch.h>
|
||||
|
@ -45,6 +45,7 @@
|
|||
#include <libaegisub/vfr.h>
|
||||
|
||||
class AegiVideoFrame;
|
||||
class AssEntry;
|
||||
class SubtitlesProviderErrorEvent;
|
||||
class ThreadedFrameSource;
|
||||
class VideoProvider;
|
||||
|
@ -139,7 +140,7 @@ class VideoContext : public wxEvtHandler {
|
|||
void OnVideoError(VideoProviderErrorEvent const& err);
|
||||
void OnSubtitlesError(SubtitlesProviderErrorEvent const& err);
|
||||
|
||||
void OnSubtitlesCommit();
|
||||
void OnSubtitlesCommit(int type, std::set<const AssEntry *> const& changed);
|
||||
void OnSubtitlesSave();
|
||||
|
||||
/// Close the video, keyframes and timecodes
|
||||
|
|
Loading…
Reference in a new issue