Delay showing the font caching dialog until subtitles are actually rendered
This commit is contained in:
parent
39626db787
commit
821f54a372
7 changed files with 71 additions and 29 deletions
|
@ -100,14 +100,21 @@ void Queue::Sync(Thunk thunk) {
|
|||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
std::unique_lock<std::mutex> l(m);
|
||||
std::exception_ptr e;
|
||||
bool done = false;
|
||||
DoInvoke([&]{
|
||||
std::unique_lock<std::mutex> l(m);
|
||||
try {
|
||||
thunk();
|
||||
}
|
||||
catch (...) {
|
||||
e = std::current_exception();
|
||||
}
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
cv.wait(l, [&]{ return done; });
|
||||
if (e) std::rethrow_exception(e);
|
||||
}
|
||||
|
||||
Queue& Main() {
|
||||
|
|
|
@ -132,10 +132,10 @@ void SubtitlesPreview::OnSize(wxSizeEvent &evt) {
|
|||
bmp = agi::util::make_unique<wxBitmap>(w, h, -1);
|
||||
vid.reset(new DummyVideoProvider(0.0, 10, w, h, back_color, true));
|
||||
try {
|
||||
if (!provider) {
|
||||
DialogProgress progress(this);
|
||||
provider = SubtitlesProviderFactory::GetProvider(&progress);
|
||||
}
|
||||
if (!progress)
|
||||
progress = agi::util::make_unique<DialogProgress>(this);
|
||||
if (!provider)
|
||||
provider = SubtitlesProviderFactory::GetProvider(progress.get());
|
||||
}
|
||||
catch (...) {
|
||||
wxMessageBox(
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
class AssFile;
|
||||
class AssStyle;
|
||||
class DialogProgress;
|
||||
class SubtitlesProvider;
|
||||
class VideoProvider;
|
||||
|
||||
|
@ -58,6 +59,8 @@ class SubtitlesPreview final : public wxWindow {
|
|||
/// Line used to render the specified text
|
||||
AssDialogue* line;
|
||||
|
||||
std::unique_ptr<DialogProgress> progress;
|
||||
|
||||
/// Regenerate the bitmap
|
||||
void UpdateBitmap();
|
||||
/// Resize event handler
|
||||
|
|
|
@ -49,11 +49,15 @@
|
|||
#include <libaegisub/log.h>
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/gil/gil_all.hpp>
|
||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <wx/intl.h>
|
||||
#include <wx/thread.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/param.h>
|
||||
#include <libaegisub/util_osx.h>
|
||||
|
@ -88,10 +92,40 @@ void msg_callback(int level, const char *fmt, va_list args, void *) {
|
|||
#define CONFIG_PATH nullptr
|
||||
#endif
|
||||
|
||||
// Stuff used on the cache thread, owned by a shared_ptr in case the provider
|
||||
// gets deleted before the cache finishing updating
|
||||
struct cache_thread_shared {
|
||||
ASS_Renderer *renderer = nullptr;
|
||||
std::atomic<bool> ready{false};
|
||||
~cache_thread_shared() { if (renderer) ass_renderer_done(renderer); }
|
||||
};
|
||||
|
||||
class LibassSubtitlesProvider final : public SubtitlesProvider {
|
||||
ASS_Renderer* ass_renderer = nullptr;
|
||||
agi::BackgroundRunner *br;
|
||||
std::shared_ptr<cache_thread_shared> shared;
|
||||
ASS_Track* ass_track = nullptr;
|
||||
|
||||
ASS_Renderer *renderer() {
|
||||
if (shared->ready)
|
||||
return shared->renderer;
|
||||
|
||||
auto block = [&]{
|
||||
br->Run([=](agi::ProgressSink *ps) {
|
||||
ps->SetTitle(from_wx(_("Updating font index")));
|
||||
ps->SetMessage(from_wx(_("This may take several minutes")));
|
||||
ps->SetIndeterminate();
|
||||
while (!shared->ready && !ps->IsCancelled())
|
||||
agi::util::sleep_for(250);
|
||||
});
|
||||
};
|
||||
|
||||
if (wxThread::IsMain())
|
||||
block();
|
||||
else
|
||||
agi::dispatch::Main().Sync(block);
|
||||
return shared->renderer;
|
||||
}
|
||||
|
||||
public:
|
||||
LibassSubtitlesProvider(agi::BackgroundRunner *br);
|
||||
~LibassSubtitlesProvider();
|
||||
|
@ -100,34 +134,24 @@ public:
|
|||
void DrawSubtitles(VideoFrame &dst, double time) override;
|
||||
};
|
||||
|
||||
LibassSubtitlesProvider::LibassSubtitlesProvider(agi::BackgroundRunner *br) {
|
||||
auto done = std::make_shared<bool>(false);
|
||||
auto renderer = std::make_shared<ASS_Renderer*>(nullptr);
|
||||
cache_queue->Async([=]{
|
||||
LibassSubtitlesProvider::LibassSubtitlesProvider(agi::BackgroundRunner *br)
|
||||
: br(br)
|
||||
, shared(std::make_shared<cache_thread_shared>())
|
||||
{
|
||||
auto state = shared;
|
||||
cache_queue->Async([state]{
|
||||
auto ass_renderer = ass_renderer_init(library);
|
||||
if (ass_renderer) {
|
||||
ass_set_font_scale(ass_renderer, 1.);
|
||||
ass_set_fonts(ass_renderer, nullptr, "Sans", 1, CONFIG_PATH, true);
|
||||
}
|
||||
*done = true;
|
||||
*renderer = ass_renderer;
|
||||
state->renderer = ass_renderer;
|
||||
state->ready = true;
|
||||
});
|
||||
|
||||
br->Run([=](agi::ProgressSink *ps) {
|
||||
ps->SetTitle(from_wx(_("Updating font index")));
|
||||
ps->SetMessage(from_wx(_("This may take several minutes")));
|
||||
ps->SetIndeterminate();
|
||||
while (!*done && !ps->IsCancelled())
|
||||
agi::util::sleep_for(250);
|
||||
});
|
||||
|
||||
ass_renderer = *renderer;
|
||||
if (!ass_renderer) throw "ass_renderer_init failed";
|
||||
}
|
||||
|
||||
LibassSubtitlesProvider::~LibassSubtitlesProvider() {
|
||||
if (ass_track) ass_free_track(ass_track);
|
||||
if (ass_renderer) ass_renderer_done(ass_renderer);
|
||||
}
|
||||
|
||||
struct Writer {
|
||||
|
@ -166,9 +190,9 @@ void LibassSubtitlesProvider::LoadSubtitles(AssFile *subs) {
|
|||
#define _a(c) ((c)&0xFF)
|
||||
|
||||
void LibassSubtitlesProvider::DrawSubtitles(VideoFrame &frame,double time) {
|
||||
ass_set_frame_size(ass_renderer, frame.width, frame.height);
|
||||
ass_set_frame_size(renderer(), frame.width, frame.height);
|
||||
|
||||
ASS_Image* img = ass_render_frame(ass_renderer, ass_track, int(time * 1000), nullptr);
|
||||
ASS_Image* img = ass_render_frame(renderer(), ass_track, int(time * 1000), nullptr);
|
||||
|
||||
// libass actually returns several alpha-masked monochrome images.
|
||||
// Here, we loop through their linked list, get the colour of the current, and blend into the frame.
|
||||
|
|
|
@ -94,7 +94,10 @@ std::shared_ptr<VideoFrame> ThreadedFrameSource::ProcFrame(int frame_number, dou
|
|||
}
|
||||
catch (std::string const& err) { throw SubtitlesProviderErrorEvent(err); }
|
||||
|
||||
try {
|
||||
subs_provider->DrawSubtitles(*frame, time / 1000.);
|
||||
}
|
||||
catch (agi::UserCancelException const&) { }
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include <libaegisub/fs.h>
|
||||
#include <libaegisub/keyframe.h>
|
||||
#include <libaegisub/path.h>
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
|
@ -123,9 +124,10 @@ void VideoContext::SetVideo(const agi::fs::path &filename) {
|
|||
|
||||
bool commit_subs = false;
|
||||
try {
|
||||
DialogProgress progress(context->parent);
|
||||
if (!progress)
|
||||
progress = new DialogProgress(context->parent);
|
||||
auto old_matrix = context->ass->GetScriptInfo("YCbCr Matrix");
|
||||
provider.reset(new ThreadedFrameSource(filename, old_matrix, this, &progress));
|
||||
provider.reset(new ThreadedFrameSource(filename, old_matrix, this, progress));
|
||||
video_provider = provider->GetVideoProvider();
|
||||
video_filename = filename;
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include <wx/timer.h>
|
||||
|
||||
class AssDialogue;
|
||||
class DialogProgress;
|
||||
class ThreadedFrameSource;
|
||||
class VideoProvider;
|
||||
struct SubtitlesProviderErrorEvent;
|
||||
|
@ -85,6 +86,8 @@ class VideoContext final : public wxEvtHandler {
|
|||
|
||||
agi::Context *context;
|
||||
|
||||
DialogProgress *progress = nullptr;
|
||||
|
||||
/// The video provider owned by the threaded frame source, or nullptr if no
|
||||
/// video is open
|
||||
VideoProvider *video_provider;
|
||||
|
|
Loading…
Reference in a new issue