#include <vector>
#include <unordered_set>
+#include "post_to_main_thread.h"
+
#include <QOpenGLFunctions>
#include <QWheelEvent>
#include <QMouseEvent>
queue.pop_front();
queued_frames = std::move(queue);
}
- current_frame.reset(new Frame(make_video_frame(frame.get())));
+ Frame *new_frame = new Frame(make_video_frame(frame.get()));
+ {
+ lock_guard lock(current_frame_mu);
+ current_frame.reset(new_frame);
+ }
update();
store_pts(frame->pts);
break;
if (frame == nullptr || error) {
return true;
}
- current_frame.reset(new Frame(make_video_frame(frame.get())));
+ Frame *new_frame = new Frame(make_video_frame(frame.get()));
+ {
+ lock_guard lock(current_frame_mu);
+ current_frame.reset(new_frame);
+ }
update();
store_pts(frame->pts);
}
void VideoWidget::paintGL()
{
- std::shared_ptr<Frame> frame = current_frame;
+ std::shared_ptr<Frame> frame;
+ {
+ lock_guard lock(current_frame_mu);
+ frame = current_frame;
+ }
if (frame == nullptr) {
glClear(GL_COLOR_BUFFER_BIT);
return;
void VideoWidget::mousePressEvent(QMouseEvent *e)
{
- if (e->button() == Qt::LeftButton) {
+ if (e->button() == Qt::BackButton) {
+ emit mouse_back_clicked();
+ } else if (e->button() == Qt::ForwardButton) {
+ emit mouse_forward_clicked();
+ } else if (e->button() == Qt::LeftButton) {
dragging = true;
last_drag_x = e->position().x();
last_drag_y = e->position().y();
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;
bool finished_wakeup;
finished_wakeup = producer_thread_should_quit.sleep_until(next_frame_start);
if (finished_wakeup) {
- current_frame.reset(new Frame(make_video_frame(frame.get())));
+ Frame *new_frame = new Frame(make_video_frame(frame.get()));
+ {
+ lock_guard lock(current_frame_mu);
+ current_frame.reset(new_frame);
+ }
last_frame = steady_clock::now();
update();
break;
if (paused) {
// Just paused, so present the frame immediately and then go into deep sleep.
- current_frame.reset(new Frame(make_video_frame(frame.get())));
+ Frame *new_frame = new Frame(make_video_frame(frame.get()));
+ {
+ lock_guard lock(current_frame_mu);
+ current_frame.reset(new_frame);
+ }
last_frame = steady_clock::now();
update();
break;
{
last_pts = pts;
last_position = lrint(pts * double(video_timebase.num) / double(video_timebase.den) * 1000);
- emit position_changed(last_position);
+ post_to_main_thread([this, last_position{last_position.load()}] {
+ emit position_changed(last_position);
+ });
}
// Taken from Movit (see the comment there for explanation)