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,6 +433,7 @@ void DialogTimingProcessor::Process() {
// Keyframe snapping // Keyframe snapping
if (keysEnable->IsChecked()) { if (keysEnable->IsChecked()) {
KeyFrames = c->videoController->GetKeyFrames(); KeyFrames = c->videoController->GetKeyFrames();
if (c->videoController->IsLoaded())
KeyFrames.push_back(c->videoController->GetLength() - 1); KeyFrames.push_back(c->videoController->GetLength() - 1);
long beforeStart = 0; long beforeStart = 0;

View file

@ -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&) {

View file

@ -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()
}; };

View file

@ -63,10 +63,8 @@ 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) {
if (val == value) return; if (val == value) return;
@ -75,10 +73,12 @@ void VideoSlider::SetValue(int value) {
} }
void VideoSlider::VideoOpened() { void VideoSlider::VideoOpened() {
if (c->videoController->IsLoaded()) {
max = c->videoController->GetLength() - 1; max = c->videoController->GetLength() - 1;
keyframes = c->videoController->GetKeyFrames(); keyframes = c->videoController->GetKeyFrames();
Refresh(false); Refresh(false);
} }
}
void VideoSlider::KeyframesChanged(std::vector<int> const& newKeyframes) { void VideoSlider::KeyframesChanged(std::vector<int> const& newKeyframes) {
keyframes = newKeyframes; keyframes = newKeyframes;