forked from mia/Aegisub
Simplify video playback logic
Originally committed to SVN as r5962.
This commit is contained in:
parent
1f534bc757
commit
2e40652265
4 changed files with 41 additions and 77 deletions
|
@ -433,7 +433,8 @@ void DialogTimingProcessor::Process() {
|
||||||
// Keyframe snapping
|
// Keyframe snapping
|
||||||
if (keysEnable->IsChecked()) {
|
if (keysEnable->IsChecked()) {
|
||||||
KeyFrames = c->videoController->GetKeyFrames();
|
KeyFrames = c->videoController->GetKeyFrames();
|
||||||
KeyFrames.push_back(c->videoController->GetLength() - 1);
|
if (c->videoController->IsLoaded())
|
||||||
|
KeyFrames.push_back(c->videoController->GetLength() - 1);
|
||||||
|
|
||||||
long beforeStart = 0;
|
long beforeStart = 0;
|
||||||
long afterStart = 0;
|
long afterStart = 0;
|
||||||
|
|
|
@ -68,26 +68,16 @@
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "video_frame.h"
|
#include "video_frame.h"
|
||||||
|
|
||||||
/// IDs
|
|
||||||
enum {
|
|
||||||
VIDEO_PLAY_TIMER = 1300
|
|
||||||
};
|
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(VideoContext, wxEvtHandler)
|
|
||||||
EVT_TIMER(VIDEO_PLAY_TIMER,VideoContext::OnPlayTimer)
|
|
||||||
END_EVENT_TABLE()
|
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
///
|
///
|
||||||
VideoContext::VideoContext()
|
VideoContext::VideoContext()
|
||||||
: startFrame(-1)
|
: playback(this)
|
||||||
, endFrame(-1)
|
, startMS(0)
|
||||||
|
, endFrame(0)
|
||||||
, playNextFrame(-1)
|
, playNextFrame(-1)
|
||||||
, nextFrame(-1)
|
, nextFrame(-1)
|
||||||
, isPlaying(false)
|
|
||||||
, keepAudioSync(true)
|
, keepAudioSync(true)
|
||||||
, frame_n(0)
|
, frame_n(0)
|
||||||
, length(0)
|
|
||||||
, arValue(1.)
|
, arValue(1.)
|
||||||
, arType(0)
|
, arType(0)
|
||||||
, hasSubtitles(false)
|
, hasSubtitles(false)
|
||||||
|
@ -97,6 +87,7 @@ VideoContext::VideoContext()
|
||||||
{
|
{
|
||||||
Bind(EVT_VIDEO_ERROR, &VideoContext::OnVideoError, this);
|
Bind(EVT_VIDEO_ERROR, &VideoContext::OnVideoError, this);
|
||||||
Bind(EVT_SUBTITLES_ERROR, &VideoContext::OnSubtitlesError, this);
|
Bind(EVT_SUBTITLES_ERROR, &VideoContext::OnSubtitlesError, this);
|
||||||
|
Bind(wxEVT_TIMER, &VideoContext::OnPlayTimer, this);
|
||||||
|
|
||||||
OPT_SUB("Subtitle/Provider", &VideoContext::Reload, this);
|
OPT_SUB("Subtitle/Provider", &VideoContext::Reload, this);
|
||||||
OPT_SUB("Video/Provider", &VideoContext::Reload, this);
|
OPT_SUB("Video/Provider", &VideoContext::Reload, this);
|
||||||
|
@ -127,9 +118,8 @@ void VideoContext::Reset() {
|
||||||
if (!ovrFPS.IsLoaded()) TimecodesOpen(videoFPS);
|
if (!ovrFPS.IsLoaded()) TimecodesOpen(videoFPS);
|
||||||
|
|
||||||
// Remove video data
|
// Remove video data
|
||||||
|
Stop();
|
||||||
frame_n = 0;
|
frame_n = 0;
|
||||||
length = 0;
|
|
||||||
isPlaying = false;
|
|
||||||
nextFrame = -1;
|
nextFrame = -1;
|
||||||
|
|
||||||
// Clean up video data
|
// Clean up video data
|
||||||
|
@ -202,9 +192,6 @@ void VideoContext::SetVideo(const wxString &filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gather video parameters
|
|
||||||
length = videoProvider->GetFrameCount();
|
|
||||||
|
|
||||||
// Set filename
|
// Set filename
|
||||||
videoName = filename;
|
videoName = filename;
|
||||||
config::mru->Add("Video", STD_STR(filename));
|
config::mru->Add("Video", STD_STR(filename));
|
||||||
|
@ -249,7 +236,7 @@ void VideoContext::Reload() {
|
||||||
void VideoContext::OnSubtitlesCommit() {
|
void VideoContext::OnSubtitlesCommit() {
|
||||||
if (!IsLoaded()) return;
|
if (!IsLoaded()) return;
|
||||||
|
|
||||||
bool wasPlaying = isPlaying;
|
bool wasPlaying = IsPlaying();
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
provider->LoadSubtitles(context->ass);
|
provider->LoadSubtitles(context->ass);
|
||||||
|
@ -285,7 +272,7 @@ void VideoContext::JumpToFrame(int n) {
|
||||||
if (!IsLoaded()) return;
|
if (!IsLoaded()) return;
|
||||||
|
|
||||||
// Prevent intervention during playback
|
// Prevent intervention during playback
|
||||||
if (isPlaying && n != playNextFrame) return;
|
if (IsPlaying() && n != playNextFrame) return;
|
||||||
|
|
||||||
frame_n = mid(0, n, GetLength() - 1);
|
frame_n = mid(0, n, GetLength() - 1);
|
||||||
|
|
||||||
|
@ -312,6 +299,10 @@ int VideoContext::GetHeight() const {
|
||||||
return videoProvider->GetHeight();
|
return videoProvider->GetHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VideoContext::GetLength() const {
|
||||||
|
return videoProvider->GetFrameCount();
|
||||||
|
}
|
||||||
|
|
||||||
void VideoContext::SaveSnapshot(bool raw) {
|
void VideoContext::SaveSnapshot(bool raw) {
|
||||||
// Get folder
|
// Get folder
|
||||||
static const agi::OptionValue* ssPath = OPT_GET("Path/Screenshot");
|
static const agi::OptionValue* ssPath = OPT_GET("Path/Screenshot");
|
||||||
|
@ -351,7 +342,7 @@ void VideoContext::SaveSnapshot(bool raw) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::NextFrame() {
|
void VideoContext::NextFrame() {
|
||||||
if (!videoProvider.get() || isPlaying || frame_n == videoProvider->GetFrameCount())
|
if (!videoProvider || IsPlaying() || frame_n == videoProvider->GetFrameCount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JumpToFrame(frame_n + 1);
|
JumpToFrame(frame_n + 1);
|
||||||
|
@ -364,7 +355,7 @@ void VideoContext::NextFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::PrevFrame() {
|
void VideoContext::PrevFrame() {
|
||||||
if (!videoProvider.get() || isPlaying || frame_n == 0)
|
if (!videoProvider || IsPlaying() || frame_n == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JumpToFrame(frame_n - 1);
|
JumpToFrame(frame_n - 1);
|
||||||
|
@ -377,7 +368,7 @@ void VideoContext::PrevFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::Play() {
|
void VideoContext::Play() {
|
||||||
if (isPlaying) {
|
if (IsPlaying()) {
|
||||||
Stop();
|
Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -385,18 +376,14 @@ void VideoContext::Play() {
|
||||||
if (!IsLoaded()) return;
|
if (!IsLoaded()) return;
|
||||||
|
|
||||||
// Set variables
|
// Set variables
|
||||||
startFrame = frame_n;
|
startMS = TimeAtFrame(frame_n);
|
||||||
endFrame = -1;
|
endFrame = GetLength() - 1;
|
||||||
|
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
context->audioController->PlayToEnd(context->audioController->SamplesFromMilliseconds(TimeAtFrame(startFrame)));
|
context->audioController->PlayToEnd(context->audioController->SamplesFromMilliseconds(startMS));
|
||||||
|
|
||||||
//audio->Play will override this if we put it before, so put it after.
|
|
||||||
isPlaying = true;
|
|
||||||
|
|
||||||
// Start timer
|
// Start timer
|
||||||
playTime.Start();
|
playTime.Start();
|
||||||
playback.SetOwner(this,VIDEO_PLAY_TIMER);
|
|
||||||
playback.Start(10);
|
playback.Start(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,55 +396,39 @@ void VideoContext::PlayLine() {
|
||||||
context->audioController->SamplesFromMilliseconds(curline->Start.GetMS()),
|
context->audioController->SamplesFromMilliseconds(curline->Start.GetMS()),
|
||||||
context->audioController->SamplesFromMilliseconds(curline->End.GetMS())));
|
context->audioController->SamplesFromMilliseconds(curline->End.GetMS())));
|
||||||
|
|
||||||
// Set variables
|
// Round-trip conversion to convert start to exact
|
||||||
isPlaying = true;
|
int startFrame = FrameAtTime(context->selectionController->GetActiveLine()->Start.GetMS(),agi::vfr::START);
|
||||||
startFrame = FrameAtTime(context->selectionController->GetActiveLine()->Start.GetMS(),agi::vfr::START);
|
startMS = TimeAtFrame(startFrame);
|
||||||
endFrame = FrameAtTime(context->selectionController->GetActiveLine()->End.GetMS(),agi::vfr::END);
|
endFrame = FrameAtTime(context->selectionController->GetActiveLine()->End.GetMS(),agi::vfr::END) + 1;
|
||||||
|
|
||||||
// Jump to start
|
// Jump to start
|
||||||
playNextFrame = startFrame;
|
playNextFrame = startFrame;
|
||||||
JumpToFrame(startFrame);
|
JumpToFrame(startFrame);
|
||||||
|
|
||||||
// Set other variables
|
|
||||||
playTime.Start();
|
|
||||||
|
|
||||||
// Start timer
|
// Start timer
|
||||||
playback.SetOwner(this,VIDEO_PLAY_TIMER);
|
playTime.Start();
|
||||||
playback.Start(10);
|
playback.Start(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::Stop() {
|
void VideoContext::Stop() {
|
||||||
if (isPlaying) {
|
if (IsPlaying()) {
|
||||||
playback.Stop();
|
playback.Stop();
|
||||||
isPlaying = false;
|
|
||||||
context->audioController->Stop();
|
context->audioController->Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::OnPlayTimer(wxTimerEvent &) {
|
void VideoContext::OnPlayTimer(wxTimerEvent &) {
|
||||||
// Get time difference
|
int nextFrame = FrameAtTime(startMS + playTime.Time());
|
||||||
int dif = playTime.Time();
|
|
||||||
|
|
||||||
// Find next frame
|
// Same frame
|
||||||
int startMs = TimeAtFrame(startFrame);
|
if (nextFrame == frame_n) return;
|
||||||
int nextFrame = frame_n;
|
|
||||||
int i=0;
|
|
||||||
for (i=0;i<10;i++) {
|
|
||||||
if (nextFrame >= length) break;
|
|
||||||
if (dif < TimeAtFrame(nextFrame) - startMs) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
nextFrame++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End
|
// End
|
||||||
if (nextFrame >= length || (endFrame != -1 && nextFrame > endFrame)) {
|
if (nextFrame >= endFrame) {
|
||||||
Stop();
|
Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same frame
|
|
||||||
if (nextFrame == frame_n) return;
|
|
||||||
|
|
||||||
// Next frame is before or over 2 frames ahead, so force audio resync
|
// Next frame is before or over 2 frames ahead, so force audio resync
|
||||||
if (context->audioController->IsPlaying() && keepAudioSync && (nextFrame < frame_n || nextFrame > frame_n + 2)) {
|
if (context->audioController->IsPlaying() && keepAudioSync && (nextFrame < frame_n || nextFrame > frame_n + 2)) {
|
||||||
|
@ -547,7 +518,7 @@ void VideoContext::LoadTimecodes(wxString filename) {
|
||||||
}
|
}
|
||||||
void VideoContext::SaveTimecodes(wxString filename) {
|
void VideoContext::SaveTimecodes(wxString filename) {
|
||||||
try {
|
try {
|
||||||
FPS().Save(STD_STR(filename), IsLoaded() ? length : -1);
|
FPS().Save(STD_STR(filename), IsLoaded() ? GetLength() : -1);
|
||||||
config::mru->Add("Timecodes", STD_STR(filename));
|
config::mru->Add("Timecodes", STD_STR(filename));
|
||||||
}
|
}
|
||||||
catch(const agi::acs::AcsError&) {
|
catch(const agi::acs::AcsError&) {
|
||||||
|
|
|
@ -95,11 +95,11 @@ class VideoContext : public wxEvtHandler {
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxTimer playback;
|
wxTimer playback;
|
||||||
|
|
||||||
/// DOCME
|
/// Time since playback was last started
|
||||||
wxStopWatch playTime;
|
wxStopWatch playTime;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int startFrame;
|
int startMS;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int endFrame;
|
int endFrame;
|
||||||
|
@ -110,18 +110,12 @@ class VideoContext : public wxEvtHandler {
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int nextFrame;
|
int nextFrame;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool isPlaying;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
bool keepAudioSync;
|
bool keepAudioSync;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int frame_n;
|
int frame_n;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int length;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
double arValue;
|
double arValue;
|
||||||
|
|
||||||
|
@ -175,10 +169,10 @@ public:
|
||||||
void SaveSnapshot(bool raw);
|
void SaveSnapshot(bool raw);
|
||||||
|
|
||||||
/// @brief Is there a video loaded?
|
/// @brief Is there a video loaded?
|
||||||
bool IsLoaded() const { return !!videoProvider.get(); }
|
bool IsLoaded() const { return !!videoProvider; }
|
||||||
|
|
||||||
/// @brief Is the video currently playing?
|
/// @brief Is the video currently playing?
|
||||||
bool IsPlaying() const { return isPlaying; }
|
bool IsPlaying() const { return playback.IsRunning(); }
|
||||||
|
|
||||||
/// @brief Does the video file loaded have muxed subtitles that we can load?
|
/// @brief Does the video file loaded have muxed subtitles that we can load?
|
||||||
bool HasSubtitles() const { return hasSubtitles; }
|
bool HasSubtitles() const { return hasSubtitles; }
|
||||||
|
@ -195,7 +189,7 @@ public:
|
||||||
int GetHeight() const;
|
int GetHeight() const;
|
||||||
|
|
||||||
/// @brief Get the length in frames of the currently open video
|
/// @brief Get the length in frames of the currently open video
|
||||||
int GetLength() const { return length; }
|
int GetLength() const;
|
||||||
|
|
||||||
/// @brief Get the current frame number
|
/// @brief Get the current frame number
|
||||||
int GetFrameN() const { return frame_n; }
|
int GetFrameN() const { return frame_n; }
|
||||||
|
@ -264,6 +258,4 @@ public:
|
||||||
|
|
||||||
static VideoContext *Get();
|
static VideoContext *Get();
|
||||||
static void OnExit();
|
static void OnExit();
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,9 +63,7 @@ VideoSlider::VideoSlider (wxWindow* parent, agi::Context *c)
|
||||||
|
|
||||||
c->videoSlider = this;
|
c->videoSlider = this;
|
||||||
|
|
||||||
if (c->videoController->IsLoaded()) {
|
VideoOpened();
|
||||||
VideoOpened();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoSlider::SetValue(int value) {
|
void VideoSlider::SetValue(int value) {
|
||||||
|
@ -75,9 +73,11 @@ void VideoSlider::SetValue(int value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoSlider::VideoOpened() {
|
void VideoSlider::VideoOpened() {
|
||||||
max = c->videoController->GetLength() - 1;
|
if (c->videoController->IsLoaded()) {
|
||||||
keyframes = c->videoController->GetKeyFrames();
|
max = c->videoController->GetLength() - 1;
|
||||||
Refresh(false);
|
keyframes = c->videoController->GetKeyFrames();
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoSlider::KeyframesChanged(std::vector<int> const& newKeyframes) {
|
void VideoSlider::KeyframesChanged(std::vector<int> const& newKeyframes) {
|
||||||
|
|
Loading…
Reference in a new issue