Example #1
0
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<VideoFrame> AsyncVideoProvider::ProcFrame(int frame_number, double time, bool raw) {
	// Find an unused buffer to use or allocate a new one if needed
	std::shared_ptr<VideoFrame> frame;
	for (auto& buffer : buffers) {
		if (buffer.use_count() == 1) {
			frame = buffer;
			break;
		}
	}

	if (!frame) {
		frame = std::make_shared<VideoFrame>();
		buffers.push_back(frame);
	}

	try {
		source_provider->GetFrame(frame_number, *frame);
	}
	catch (VideoProviderError const& err) { throw VideoProviderErrorEvent(err); }

	if (raw || !subs_provider || !subs) return frame;

	try {
		if (single_frame != frame_number && single_frame != SUBS_FILE_ALREADY_LOADED) {
			// 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 (single_frame != NEW_SUBS_FILE) {
				subs_provider->LoadSubtitles(subs.get());
				single_frame = SUBS_FILE_ALREADY_LOADED;
			}
			else {
				AssFixStylesFilter::ProcessSubs(subs.get());
				single_frame = frame_number;
				subs_provider->LoadSubtitles(subs.get(), time);
			}
		}
	}
	catch (agi::Exception const& err) { throw SubtitlesProviderErrorEvent(err.GetMessage()); }

	try {
		subs_provider->DrawSubtitles(*frame, time / 1000.);
	}
	catch (agi::UserCancelException const&) { }

	return frame;
}
std::shared_ptr<VideoFrame> ThreadedFrameSource::ProcFrame(int frame_number, double time, bool raw) {
	std::shared_ptr<VideoFrame> frame;

	try {
		frame = video_provider->GetFrame(frame_number);
	}
	catch (VideoProviderError const& err) { throw VideoProviderErrorEvent(err); }

	if (raw || !subs_provider || !subs) return frame;

	try {
		if (single_frame != frame_number && single_frame != SUBS_FILE_ALREADY_LOADED) {
			// 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 (single_frame != NEW_SUBS_FILE) {
				subs_provider->LoadSubtitles(subs.get());
				single_frame = SUBS_FILE_ALREADY_LOADED;
			}
			else {
				AssFixStylesFilter().ProcessSubs(subs.get(), nullptr);
				single_frame = frame_number;
				subs_provider->LoadSubtitles(subs.get(), time);
			}
		}
	}
	catch (std::string const& err) { throw SubtitlesProviderErrorEvent(err); }

	try {
		subs_provider->DrawSubtitles(*frame, time / 1000.);
	}
	catch (agi::UserCancelException const&) { }

	return frame;
}
Example #4
0
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;
}