std::tr1::shared_ptr<AegiVideoFrame> ThreadedFrameSource::ProcFrame(int frameNum, double time, bool raw) { std::tr1::shared_ptr<AegiVideoFrame> frame(new AegiVideoFrame, delete_frame); { wxMutexLocker locker(providerMutex); try { frame->CopyFrom(videoProvider->GetFrame(frameNum)); } catch (VideoProviderError const& err) { throw VideoProviderErrorEvent(err); } } // This deliberately results in a call to LoadSubtitles while a render // is pending making the queued render use the new file if (!raw) { try { wxMutexLocker locker(fileMutex); if (subs.get() && singleFrame != frameNum) { // Generally edits and seeks come in groups; if the last thing done // was seek it is more likely that the user will seek again and // vice versa. As such, if this is the first frame requested after // an edit, only export the currently visible lines (because the // other lines will probably not be viewed before the file changes // again), and if it's a different frame, export the entire file. if (singleFrame == -1) { AssExporter exporter(subs.get()); exporter.AddAutoFilters(); exporter.ExportTransform(); singleFrame = frameNum; // Copying a nontrivially sized AssFile is fairly slow, so // instead muck around with its innards to just temporarily // remove the non-visible lines without deleting them std::list<AssEntry*> visible; std::remove_copy_if(subs->Line.begin(), subs->Line.end(), std::back_inserter(visible), invisible_line(time)); try { std::swap(subs->Line, visible); provider->LoadSubtitles(subs.get()); std::swap(subs->Line, visible); } catch(...) { std::swap(subs->Line, visible); throw; } } else { provider->LoadSubtitles(subs.get()); subs.reset(); } } } catch (wxString const& err) { throw SubtitlesProviderErrorEvent(err); } provider->DrawSubtitles(*frame, time); } return frame; }
std::shared_ptr<AegiVideoFrame> ThreadedFrameSource::ProcFrame(int frameNum, double time, bool raw) { std::shared_ptr<AegiVideoFrame> frame(new AegiVideoFrame, [](AegiVideoFrame *frame) { frame->Clear(); delete frame; }); { wxMutexLocker locker(providerMutex); try { frame->CopyFrom(videoProvider->GetFrame(frameNum)); } catch (VideoProviderError const& err) { throw VideoProviderErrorEvent(err); } } // This deliberately results in a call to LoadSubtitles while a render // is pending making the queued render use the new file if (!raw && provider) { try { wxMutexLocker locker(fileMutex); if (subs.get() && singleFrame != frameNum) { // Generally edits and seeks come in groups; if the last thing done // was seek it is more likely that the user will seek again and // vice versa. As such, if this is the first frame requested after // an edit, only export the currently visible lines (because the // other lines will probably not be viewed before the file changes // again), and if it's a different frame, export the entire file. if (singleFrame == -1) { // This will crash if any of the export filters try to use // anything but the subtitles, but that wouldn't be safe to // do anyway agi::Context c; memset(&c, 0, sizeof c); c.ass = subs.get(); AssExporter exporter(&c); exporter.AddAutoFilters(); exporter.ExportTransform(); singleFrame = frameNum; // Copying a nontrivially sized AssFile is fairly slow, so // instead muck around with its innards to just temporarily // remove the non-visible lines without deleting them std::deque<AssEntry*> full; for (auto& line : subs->Line) full.push_back(&line); subs->Line.remove_if(invisible_line(time)); try { provider->LoadSubtitles(subs.get()); subs->Line.clear(); boost::push_back(subs->Line, full | boost::adaptors::indirected); } catch(...) { subs->Line.clear(); boost::push_back(subs->Line, full | boost::adaptors::indirected); throw; } } else { provider->LoadSubtitles(subs.get()); subs.reset(); } } } catch (wxString const& err) { throw SubtitlesProviderErrorEvent(err); } provider->DrawSubtitles(*frame, time); } return frame; }