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::mutex m;
|
||||||
std::condition_variable cv;
|
std::condition_variable cv;
|
||||||
std::unique_lock<std::mutex> l(m);
|
std::unique_lock<std::mutex> l(m);
|
||||||
|
std::exception_ptr e;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
DoInvoke([&]{
|
DoInvoke([&]{
|
||||||
std::unique_lock<std::mutex> l(m);
|
std::unique_lock<std::mutex> l(m);
|
||||||
thunk();
|
try {
|
||||||
|
thunk();
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
e = std::current_exception();
|
||||||
|
}
|
||||||
done = true;
|
done = true;
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
});
|
});
|
||||||
cv.wait(l, [&]{ return done; });
|
cv.wait(l, [&]{ return done; });
|
||||||
|
if (e) std::rethrow_exception(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Queue& Main() {
|
Queue& Main() {
|
||||||
|
|
|
@ -132,10 +132,10 @@ void SubtitlesPreview::OnSize(wxSizeEvent &evt) {
|
||||||
bmp = agi::util::make_unique<wxBitmap>(w, h, -1);
|
bmp = agi::util::make_unique<wxBitmap>(w, h, -1);
|
||||||
vid.reset(new DummyVideoProvider(0.0, 10, w, h, back_color, true));
|
vid.reset(new DummyVideoProvider(0.0, 10, w, h, back_color, true));
|
||||||
try {
|
try {
|
||||||
if (!provider) {
|
if (!progress)
|
||||||
DialogProgress progress(this);
|
progress = agi::util::make_unique<DialogProgress>(this);
|
||||||
provider = SubtitlesProviderFactory::GetProvider(&progress);
|
if (!provider)
|
||||||
}
|
provider = SubtitlesProviderFactory::GetProvider(progress.get());
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
wxMessageBox(
|
wxMessageBox(
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
class AssFile;
|
class AssFile;
|
||||||
class AssStyle;
|
class AssStyle;
|
||||||
|
class DialogProgress;
|
||||||
class SubtitlesProvider;
|
class SubtitlesProvider;
|
||||||
class VideoProvider;
|
class VideoProvider;
|
||||||
|
|
||||||
|
@ -58,6 +59,8 @@ class SubtitlesPreview final : public wxWindow {
|
||||||
/// Line used to render the specified text
|
/// Line used to render the specified text
|
||||||
AssDialogue* line;
|
AssDialogue* line;
|
||||||
|
|
||||||
|
std::unique_ptr<DialogProgress> progress;
|
||||||
|
|
||||||
/// Regenerate the bitmap
|
/// Regenerate the bitmap
|
||||||
void UpdateBitmap();
|
void UpdateBitmap();
|
||||||
/// Resize event handler
|
/// Resize event handler
|
||||||
|
|
|
@ -49,11 +49,15 @@
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
#include <libaegisub/util.h>
|
#include <libaegisub/util.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <boost/gil/gil_all.hpp>
|
#include <boost/gil/gil_all.hpp>
|
||||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <wx/intl.h>
|
||||||
|
#include <wx/thread.h>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <libaegisub/util_osx.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
|
#define CONFIG_PATH nullptr
|
||||||
#endif
|
#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 {
|
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_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:
|
public:
|
||||||
LibassSubtitlesProvider(agi::BackgroundRunner *br);
|
LibassSubtitlesProvider(agi::BackgroundRunner *br);
|
||||||
~LibassSubtitlesProvider();
|
~LibassSubtitlesProvider();
|
||||||
|
@ -100,34 +134,24 @@ public:
|
||||||
void DrawSubtitles(VideoFrame &dst, double time) override;
|
void DrawSubtitles(VideoFrame &dst, double time) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
LibassSubtitlesProvider::LibassSubtitlesProvider(agi::BackgroundRunner *br) {
|
LibassSubtitlesProvider::LibassSubtitlesProvider(agi::BackgroundRunner *br)
|
||||||
auto done = std::make_shared<bool>(false);
|
: br(br)
|
||||||
auto renderer = std::make_shared<ASS_Renderer*>(nullptr);
|
, shared(std::make_shared<cache_thread_shared>())
|
||||||
cache_queue->Async([=]{
|
{
|
||||||
|
auto state = shared;
|
||||||
|
cache_queue->Async([state]{
|
||||||
auto ass_renderer = ass_renderer_init(library);
|
auto ass_renderer = ass_renderer_init(library);
|
||||||
if (ass_renderer) {
|
if (ass_renderer) {
|
||||||
ass_set_font_scale(ass_renderer, 1.);
|
ass_set_font_scale(ass_renderer, 1.);
|
||||||
ass_set_fonts(ass_renderer, nullptr, "Sans", 1, CONFIG_PATH, true);
|
ass_set_fonts(ass_renderer, nullptr, "Sans", 1, CONFIG_PATH, true);
|
||||||
}
|
}
|
||||||
*done = true;
|
state->renderer = ass_renderer;
|
||||||
*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() {
|
LibassSubtitlesProvider::~LibassSubtitlesProvider() {
|
||||||
if (ass_track) ass_free_track(ass_track);
|
if (ass_track) ass_free_track(ass_track);
|
||||||
if (ass_renderer) ass_renderer_done(ass_renderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Writer {
|
struct Writer {
|
||||||
|
@ -166,9 +190,9 @@ void LibassSubtitlesProvider::LoadSubtitles(AssFile *subs) {
|
||||||
#define _a(c) ((c)&0xFF)
|
#define _a(c) ((c)&0xFF)
|
||||||
|
|
||||||
void LibassSubtitlesProvider::DrawSubtitles(VideoFrame &frame,double time) {
|
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.
|
// 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.
|
// 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); }
|
catch (std::string const& err) { throw SubtitlesProviderErrorEvent(err); }
|
||||||
|
|
||||||
subs_provider->DrawSubtitles(*frame, time / 1000.);
|
try {
|
||||||
|
subs_provider->DrawSubtitles(*frame, time / 1000.);
|
||||||
|
}
|
||||||
|
catch (agi::UserCancelException const&) { }
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include <libaegisub/fs.h>
|
#include <libaegisub/fs.h>
|
||||||
#include <libaegisub/keyframe.h>
|
#include <libaegisub/keyframe.h>
|
||||||
#include <libaegisub/path.h>
|
#include <libaegisub/path.h>
|
||||||
|
#include <libaegisub/util.h>
|
||||||
|
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
|
||||||
|
@ -123,9 +124,10 @@ void VideoContext::SetVideo(const agi::fs::path &filename) {
|
||||||
|
|
||||||
bool commit_subs = false;
|
bool commit_subs = false;
|
||||||
try {
|
try {
|
||||||
DialogProgress progress(context->parent);
|
if (!progress)
|
||||||
|
progress = new DialogProgress(context->parent);
|
||||||
auto old_matrix = context->ass->GetScriptInfo("YCbCr Matrix");
|
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_provider = provider->GetVideoProvider();
|
||||||
video_filename = filename;
|
video_filename = filename;
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
|
|
||||||
class AssDialogue;
|
class AssDialogue;
|
||||||
|
class DialogProgress;
|
||||||
class ThreadedFrameSource;
|
class ThreadedFrameSource;
|
||||||
class VideoProvider;
|
class VideoProvider;
|
||||||
struct SubtitlesProviderErrorEvent;
|
struct SubtitlesProviderErrorEvent;
|
||||||
|
@ -85,6 +86,8 @@ class VideoContext final : public wxEvtHandler {
|
||||||
|
|
||||||
agi::Context *context;
|
agi::Context *context;
|
||||||
|
|
||||||
|
DialogProgress *progress = nullptr;
|
||||||
|
|
||||||
/// The video provider owned by the threaded frame source, or nullptr if no
|
/// The video provider owned by the threaded frame source, or nullptr if no
|
||||||
/// video is open
|
/// video is open
|
||||||
VideoProvider *video_provider;
|
VideoProvider *video_provider;
|
||||||
|
|
Loading…
Reference in a new issue