zoom_matrix[7] = std::max(zoom_matrix[7], 1.0 - zoom_matrix[4]); // Top side (y=1).
}
-void VideoWidget::open(const string &filename)
+bool VideoWidget::open(const string &filename)
{
stop();
internal_rewind();
pathname = filename;
play();
+
+ while (running == STARTING) {
+ // Poor man's condition variable...
+ usleep(10000);
+ sched_yield();
+ }
+ return (running != VIDEO_FILE_ERROR);
}
void VideoWidget::play()
{
- if (running) {
+ if (running != NOT_RUNNING && running != VIDEO_FILE_ERROR) {
std::lock_guard<std::mutex> lock(queue_mu);
command_queue.push_back(QueuedCommand { QueuedCommand::RESUME });
producer_thread_should_quit.wakeup();
return;
}
- running = true;
+ running = STARTING;
producer_thread_should_quit.unquit();
+ if (producer_thread.joinable()) {
+ producer_thread.join();
+ }
producer_thread = std::thread(&VideoWidget::producer_thread_func, this);
}
void VideoWidget::pause()
{
- if (!running) {
+ if (running == NOT_RUNNING || running == VIDEO_FILE_ERROR) {
return;
}
std::lock_guard<std::mutex> lock(queue_mu);
void VideoWidget::seek(int64_t relative_seek_ms)
{
- if (!running) {
+ if (running == NOT_RUNNING || running == VIDEO_FILE_ERROR) {
return;
}
std::lock_guard<std::mutex> lock(queue_mu);
void VideoWidget::seek_frames(int64_t relative_seek_frames)
{
- if (!running) {
+ if (running == NOT_RUNNING || running == VIDEO_FILE_ERROR) {
return;
}
std::lock_guard<std::mutex> lock(queue_mu);
void VideoWidget::seek_absolute(int64_t position_ms)
{
- if (!running) {
+ if (running == NOT_RUNNING || running == VIDEO_FILE_ERROR) {
return;
}
std::lock_guard<std::mutex> lock(queue_mu);
void VideoWidget::stop()
{
- if (!running) {
+ if (running == NOT_RUNNING || running == VIDEO_FILE_ERROR) {
return;
}
- running = false;
producer_thread_should_quit.quit();
producer_thread.join();
}
{
if (!producer_thread_should_quit.should_quit()) {
if (!play_video(pathname)) {
- // TODO: Send the error back to the UI somehow.
+ running = VIDEO_FILE_ERROR;
+ } else {
+ running = NOT_RUNNING;
}
}
}
internal_rewind();
+ running = RUNNING;
+
// Main loop.
int consecutive_errors = 0;
double rate = 1.0;
VideoWidget(QWidget *parent);
~VideoWidget() { stop(); }
- void open(const std::string &filename);
+ bool open(const std::string &filename); // False on error.
void play();
uint64_t get_position() const { return last_position; } // In milliseconds.
void pause();
int64_t pts_origin;
int64_t last_pts;
std::atomic<uint64_t> last_position{0}; // TODO: sort of redundant wrt. last_pts (but this one can be read from the other thread)
- std::atomic<bool> running{false};
+ enum RunState { NOT_RUNNING, STARTING, RUNNING, VIDEO_FILE_ERROR }; // NOT_RUNNING and VIDEO_FILE_ERROR both imply that the thread isn't running and can freely be restarted.
+ std::atomic<RunState> running{NOT_RUNNING};
bool paused = false;
std::chrono::steady_clock::time_point start, next_frame_start, last_frame;