Simplify video playback logic

Originally committed to SVN as r5962.
This commit is contained in:
Thomas Goyne 2011-12-05 05:26:45 +00:00
parent 1f534bc757
commit 2e40652265
4 changed files with 41 additions and 77 deletions

View File

@ -433,7 +433,8 @@ void DialogTimingProcessor::Process() {
// Keyframe snapping
if (keysEnable->IsChecked()) {
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 afterStart = 0;

View File

@ -68,26 +68,16 @@
#include "video_context.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
///
VideoContext::VideoContext()
: startFrame(-1)
, endFrame(-1)
: playback(this)
, startMS(0)
, endFrame(0)
, playNextFrame(-1)
, nextFrame(-1)
, isPlaying(false)
, keepAudioSync(true)
, frame_n(0)
, length(0)
, arValue(1.)
, arType(0)
, hasSubtitles(false)
@ -97,6 +87,7 @@ VideoContext::VideoContext()
{
Bind(EVT_VIDEO_ERROR, &VideoContext::OnVideoError, this);
Bind(EVT_SUBTITLES_ERROR, &VideoContext::OnSubtitlesError, this);
Bind(wxEVT_TIMER, &VideoContext::OnPlayTimer, this);
OPT_SUB("Subtitle/Provider", &VideoContext::Reload, this);
OPT_SUB("Video/Provider", &VideoContext::Reload, this);
@ -127,9 +118,8 @@ void VideoContext::Reset() {
if (!ovrFPS.IsLoaded()) TimecodesOpen(videoFPS);
// Remove video data
Stop();
frame_n = 0;
length = 0;
isPlaying = false;
nextFrame = -1;
// Clean up video data
@ -202,9 +192,6 @@ void VideoContext::SetVideo(const wxString &filename) {
}
}
// Gather video parameters
length = videoProvider->GetFrameCount();
// Set filename
videoName = filename;
config::mru->Add("Video", STD_STR(filename));
@ -249,7 +236,7 @@ void VideoContext::Reload() {
void VideoContext::OnSubtitlesCommit() {
if (!IsLoaded()) return;
bool wasPlaying = isPlaying;
bool wasPlaying = IsPlaying();
Stop();
provider->LoadSubtitles(context->ass);
@ -285,7 +272,7 @@ void VideoContext::JumpToFrame(int n) {
if (!IsLoaded()) return;
// Prevent intervention during playback
if (isPlaying && n != playNextFrame) return;
if (IsPlaying() && n != playNextFrame) return;
frame_n = mid(0, n, GetLength() - 1);
@ -312,6 +299,10 @@ int VideoContext::GetHeight() const {
return videoProvider->GetHeight();
}
int VideoContext::GetLength() const {
return videoProvider->GetFrameCount();
}
void VideoContext::SaveSnapshot(bool raw) {
// Get folder
static const agi::OptionValue* ssPath = OPT_GET("Path/Screenshot");
@ -351,7 +342,7 @@ void VideoContext::SaveSnapshot(bool raw) {
}
void VideoContext::NextFrame() {
if (!videoProvider.get() || isPlaying || frame_n == videoProvider->GetFrameCount())
if (!videoProvider || IsPlaying() || frame_n == videoProvider->GetFrameCount())
return;
JumpToFrame(frame_n + 1);
@ -364,7 +355,7 @@ void VideoContext::NextFrame() {
}
void VideoContext::PrevFrame() {
if (!videoProvider.get() || isPlaying || frame_n == 0)
if (!videoProvider || IsPlaying() || frame_n == 0)
return;
JumpToFrame(frame_n - 1);
@ -377,7 +368,7 @@ void VideoContext::PrevFrame() {
}
void VideoContext::Play() {
if (isPlaying) {
if (IsPlaying()) {
Stop();
return;
}
@ -385,18 +376,14 @@ void VideoContext::Play() {
if (!IsLoaded()) return;
// Set variables
startFrame = frame_n;
endFrame = -1;
startMS = TimeAtFrame(frame_n);
endFrame = GetLength() - 1;
// Start playing audio
context->audioController->PlayToEnd(context->audioController->SamplesFromMilliseconds(TimeAtFrame(startFrame)));
//audio->Play will override this if we put it before, so put it after.
isPlaying = true;
context->audioController->PlayToEnd(context->audioController->SamplesFromMilliseconds(startMS));
// Start timer
playTime.Start();
playback.SetOwner(this,VIDEO_PLAY_TIMER);
playback.Start(10);
}
@ -409,55 +396,39 @@ void VideoContext::PlayLine() {
context->audioController->SamplesFromMilliseconds(curline->Start.GetMS()),
context->audioController->SamplesFromMilliseconds(curline->End.GetMS())));
// Set variables
isPlaying = true;
startFrame = FrameAtTime(context->selectionController->GetActiveLine()->Start.GetMS(),agi::vfr::START);
endFrame = FrameAtTime(context->selectionController->GetActiveLine()->End.GetMS(),agi::vfr::END);
// Round-trip conversion to convert start to exact
int startFrame = FrameAtTime(context->selectionController->GetActiveLine()->Start.GetMS(),agi::vfr::START);
startMS = TimeAtFrame(startFrame);
endFrame = FrameAtTime(context->selectionController->GetActiveLine()->End.GetMS(),agi::vfr::END) + 1;
// Jump to start
playNextFrame = startFrame;
JumpToFrame(startFrame);
// Set other variables
playTime.Start();
// Start timer
playback.SetOwner(this,VIDEO_PLAY_TIMER);
playTime.Start();
playback.Start(10);
}
void VideoContext::Stop() {
if (isPlaying) {
if (IsPlaying()) {
playback.Stop();
isPlaying = false;
context->audioController->Stop();
}
}
void VideoContext::OnPlayTimer(wxTimerEvent &) {
// Get time difference
int dif = playTime.Time();
int nextFrame = FrameAtTime(startMS + playTime.Time());
// Find next frame
int startMs = TimeAtFrame(startFrame);
int nextFrame = frame_n;
int i=0;
for (i=0;i<10;i++) {
if (nextFrame >= length) break;
if (dif < TimeAtFrame(nextFrame) - startMs) {
break;
}
nextFrame++;
}
// Same frame
if (nextFrame == frame_n) return;
// End
if (nextFrame >= length || (endFrame != -1 && nextFrame > endFrame)) {
if (nextFrame >= endFrame) {
Stop();
return;
}
// Same frame
if (nextFrame == frame_n) return;
// 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)) {
@ -547,7 +518,7 @@ void VideoContext::LoadTimecodes(wxString filename) {
}
void VideoContext::SaveTimecodes(wxString filename) {
try {
FPS().Save(STD_STR(filename), IsLoaded() ? length : -1);
FPS().Save(STD_STR(filename), IsLoaded() ? GetLength() : -1);
config::mru->Add("Timecodes", STD_STR(filename));
}
catch(const agi::acs::AcsError&) {

View File

@ -95,11 +95,11 @@ class VideoContext : public wxEvtHandler {
/// DOCME
wxTimer playback;
/// DOCME
/// Time since playback was last started
wxStopWatch playTime;
/// DOCME
int startFrame;
int startMS;
/// DOCME
int endFrame;
@ -110,18 +110,12 @@ class VideoContext : public wxEvtHandler {
/// DOCME
int nextFrame;
/// DOCME
bool isPlaying;
/// DOCME
bool keepAudioSync;
/// DOCME
int frame_n;
/// DOCME
int length;
/// DOCME
double arValue;
@ -175,10 +169,10 @@ public:
void SaveSnapshot(bool raw);
/// @brief Is there a video loaded?
bool IsLoaded() const { return !!videoProvider.get(); }
bool IsLoaded() const { return !!videoProvider; }
/// @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?
bool HasSubtitles() const { return hasSubtitles; }
@ -195,7 +189,7 @@ public:
int GetHeight() const;
/// @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
int GetFrameN() const { return frame_n; }
@ -264,6 +258,4 @@ public:
static VideoContext *Get();
static void OnExit();
DECLARE_EVENT_TABLE()
};

View File

@ -63,9 +63,7 @@ VideoSlider::VideoSlider (wxWindow* parent, agi::Context *c)
c->videoSlider = this;
if (c->videoController->IsLoaded()) {
VideoOpened();
}
VideoOpened();
}
void VideoSlider::SetValue(int value) {
@ -75,9 +73,11 @@ void VideoSlider::SetValue(int value) {
}
void VideoSlider::VideoOpened() {
max = c->videoController->GetLength() - 1;
keyframes = c->videoController->GetKeyFrames();
Refresh(false);
if (c->videoController->IsLoaded()) {
max = c->videoController->GetLength() - 1;
keyframes = c->videoController->GetKeyFrames();
Refresh(false);
}
}
void VideoSlider::KeyframesChanged(std::vector<int> const& newKeyframes) {