2012-12-02 22:14:24 +01:00
|
|
|
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
|
2010-07-23 07:58:39 +02:00
|
|
|
//
|
2012-12-02 22:14:24 +01:00
|
|
|
// Permission to use, copy, modify, and distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice appear in all copies.
|
2010-07-23 07:58:39 +02:00
|
|
|
//
|
2012-12-02 22:14:24 +01:00
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2010-07-23 07:58:39 +02:00
|
|
|
//
|
|
|
|
// Aegisub Project http://www.aegisub.org/
|
|
|
|
|
|
|
|
/// @file threaded_frame_source.h
|
|
|
|
/// @see threaded_frame_source.cpp
|
|
|
|
/// @ingroup video
|
|
|
|
///
|
|
|
|
|
2012-12-17 17:27:11 +01:00
|
|
|
#include <deque>
|
2012-09-25 01:35:27 +02:00
|
|
|
#include <memory>
|
2012-12-17 17:27:11 +01:00
|
|
|
#include <set>
|
2010-07-23 07:58:39 +02:00
|
|
|
|
|
|
|
#include <wx/event.h>
|
|
|
|
#include <wx/thread.h>
|
|
|
|
|
|
|
|
#include <libaegisub/exception.h>
|
2011-12-22 22:29:29 +01:00
|
|
|
#include <libaegisub/scoped_ptr.h>
|
|
|
|
|
2012-01-18 21:08:42 +01:00
|
|
|
class AegiVideoFrame;
|
2012-12-17 17:27:11 +01:00
|
|
|
class AssEntry;
|
2010-07-23 07:58:39 +02:00
|
|
|
class AssFile;
|
|
|
|
class SubtitlesProvider;
|
|
|
|
class VideoProvider;
|
2010-08-02 08:32:01 +02:00
|
|
|
class VideoProviderError;
|
2010-07-23 07:58:39 +02:00
|
|
|
|
|
|
|
/// @class ThreadedFrameSource
|
|
|
|
/// @brief An asynchronous video decoding and subtitle rendering wrapper
|
|
|
|
class ThreadedFrameSource : public wxThread {
|
|
|
|
/// Subtitles provider
|
2011-12-22 22:29:29 +01:00
|
|
|
agi::scoped_ptr<SubtitlesProvider> provider;
|
2010-07-23 07:58:39 +02:00
|
|
|
/// Video provider
|
2011-12-22 22:29:29 +01:00
|
|
|
agi::scoped_ptr<VideoProvider> videoProvider;
|
2010-07-23 07:58:39 +02:00
|
|
|
/// Event handler to send FrameReady events to
|
|
|
|
wxEvtHandler *parent;
|
|
|
|
|
|
|
|
int nextFrame; ///< Next queued frame, or -1 for none
|
|
|
|
double nextTime; ///< Next queued time
|
2012-11-16 00:46:56 +01:00
|
|
|
std::unique_ptr<AssFile> nextSubs; ///< Next queued AssFile
|
2012-12-17 17:27:11 +01:00
|
|
|
std::deque<std::pair<size_t, std::unique_ptr<AssEntry>>> changedSubs;
|
2010-07-23 07:58:39 +02:00
|
|
|
|
|
|
|
/// Subtitles to be loaded the next time a frame is requested
|
2012-11-16 00:46:56 +01:00
|
|
|
std::unique_ptr<AssFile> subs;
|
2010-07-23 07:58:39 +02:00
|
|
|
/// If subs is set and this is not -1, frame which subs was limited to when
|
|
|
|
/// it was last sent to the subtitle provider
|
|
|
|
int singleFrame;
|
|
|
|
|
2010-12-30 23:19:36 +01:00
|
|
|
wxMutex fileMutex; ///< Mutex for subs and singleFrame
|
|
|
|
wxMutex jobMutex; ///< Mutex for nextFrame, nextTime and nextSubs
|
2010-07-23 07:58:39 +02:00
|
|
|
wxMutex providerMutex; ///< Mutex for video provider
|
|
|
|
wxMutex evtMutex; ///< Mutex for FrameReadyEvents associated with this
|
|
|
|
|
|
|
|
wxCondition jobReady; ///< Signal for indicating that a frame has be requested
|
|
|
|
|
|
|
|
bool run; ///< Should the thread continue to run
|
|
|
|
|
|
|
|
void *Entry();
|
2012-09-25 01:35:27 +02:00
|
|
|
std::shared_ptr<AegiVideoFrame> ProcFrame(int frameNum, double time, bool raw = false);
|
2010-07-23 07:58:39 +02:00
|
|
|
public:
|
|
|
|
/// @brief Load the passed subtitle file
|
|
|
|
/// @param subs File to load
|
|
|
|
///
|
|
|
|
/// This function blocks until is it is safe for the calling thread to
|
|
|
|
/// modify subs
|
2012-12-17 17:27:11 +01:00
|
|
|
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();
|
2010-07-23 07:58:39 +02:00
|
|
|
|
|
|
|
/// @brief Queue a request for a frame
|
|
|
|
/// @brief frame Frame number
|
|
|
|
/// @brief time Exact start time of the frame in seconds
|
|
|
|
///
|
|
|
|
/// This merely queues up a request and deletes any pending requests; there
|
|
|
|
/// is no guarantee that the requested frame will ever actually be produced
|
|
|
|
void RequestFrame(int frame, double time) throw();
|
|
|
|
|
|
|
|
/// @brief Synchronously get a frame
|
|
|
|
/// @brief frame Frame number
|
|
|
|
/// @brief time Exact start time of the frame in seconds
|
|
|
|
/// @brief raw Get raw frame without subtitles
|
2012-09-25 01:35:27 +02:00
|
|
|
std::shared_ptr<AegiVideoFrame> GetFrame(int frame, double time, bool raw = false);
|
2010-07-23 07:58:39 +02:00
|
|
|
|
2011-12-06 01:17:36 +01:00
|
|
|
/// Get a reference to the video provider this is using
|
|
|
|
VideoProvider *GetVideoProvider() const { return videoProvider.get(); }
|
2010-07-23 07:58:39 +02:00
|
|
|
|
|
|
|
/// @brief Constructor
|
|
|
|
/// @param videoFileName File to open
|
|
|
|
/// @param parent Event handler to send FrameReady events to
|
|
|
|
ThreadedFrameSource(wxString videoFileName, wxEvtHandler *parent);
|
|
|
|
~ThreadedFrameSource();
|
|
|
|
};
|
|
|
|
|
|
|
|
/// @class FrameReadyEvent
|
|
|
|
/// @brief Event which signals that a requested frame is ready
|
|
|
|
class FrameReadyEvent : public wxEvent {
|
|
|
|
public:
|
2010-09-16 00:10:48 +02:00
|
|
|
/// Frame which is ready
|
2012-09-25 01:35:27 +02:00
|
|
|
std::shared_ptr<AegiVideoFrame> frame;
|
2010-07-23 07:58:39 +02:00
|
|
|
/// Time which was used for subtitle rendering
|
|
|
|
double time;
|
|
|
|
wxEvent *Clone() const { return new FrameReadyEvent(*this); };
|
2012-09-25 01:35:27 +02:00
|
|
|
FrameReadyEvent(std::shared_ptr<AegiVideoFrame> frame, double time)
|
2010-09-16 00:10:48 +02:00
|
|
|
: frame(frame), time(time) {
|
2010-07-23 07:58:39 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// These exceptions are wxEvents so that they can be passed directly back to
|
|
|
|
// the parent thread as events
|
|
|
|
class VideoProviderErrorEvent : public wxEvent, public agi::Exception {
|
|
|
|
public:
|
|
|
|
const char * GetName() const { return "video/error"; }
|
|
|
|
wxEvent *Clone() const { return new VideoProviderErrorEvent(*this); };
|
|
|
|
agi::Exception *Copy() const { return new VideoProviderErrorEvent(*this); };
|
2010-08-02 08:32:01 +02:00
|
|
|
VideoProviderErrorEvent(VideoProviderError const& err);
|
2010-07-23 07:58:39 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class SubtitlesProviderErrorEvent : public wxEvent, public agi::Exception {
|
|
|
|
public:
|
|
|
|
const char * GetName() const { return "subtitles/error"; }
|
|
|
|
wxEvent *Clone() const { return new SubtitlesProviderErrorEvent(*this); };
|
|
|
|
agi::Exception *Copy() const { return new SubtitlesProviderErrorEvent(*this); };
|
|
|
|
SubtitlesProviderErrorEvent(wxString msg);
|
|
|
|
};
|
|
|
|
|
2010-07-23 08:21:22 +02:00
|
|
|
wxDECLARE_EVENT(EVT_FRAME_READY, FrameReadyEvent);
|
|
|
|
wxDECLARE_EVENT(EVT_VIDEO_ERROR, VideoProviderErrorEvent);
|
|
|
|
wxDECLARE_EVENT(EVT_SUBTITLES_ERROR, SubtitlesProviderErrorEvent);
|