From d9913b0d39d6ea0362f31157e5979ffa351f3888 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 11 Jun 2018 20:32:07 +0200 Subject: [PATCH] Add some very basic playback. --- Makefile | 2 +- clip_list.h | 1 + defs.h | 6 +++ main.cpp | 13 +++--- mainwindow.cpp | 10 +++-- player.cpp | 109 +++++++++++++++++++++++++++++++++++++++++++++++ player.h | 9 ++++ ui_mainwindow.ui | 4 +- 8 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 defs.h create mode 100644 player.cpp create mode 100644 player.h diff --git a/Makefile b/Makefile index fc91d0e..42b5ea0 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ OBJS_WITH_MOC = mainwindow.o jpeg_frame_view.o clip_list.o OBJS += $(OBJS_WITH_MOC) OBJS += $(OBJS_WITH_MOC:.o=.moc.o) -OBJS += ffmpeg_raii.o main.o +OBJS += ffmpeg_raii.o main.o player.o %.o: %.cpp $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< diff --git a/clip_list.h b/clip_list.h index cb58564..da76f8c 100644 --- a/clip_list.h +++ b/clip_list.h @@ -37,6 +37,7 @@ public: } } Clip *operator->() { return &clip; } + Clip &operator*() { return clip; } private: Clip &clip; diff --git a/defs.h b/defs.h new file mode 100644 index 0000000..798e5f1 --- /dev/null +++ b/defs.h @@ -0,0 +1,6 @@ +#ifndef _DEFS_H +#define _DEFS_H 1 + +#define MAX_STREAMS 16 + +#endif // !defined(_DEFS_H) diff --git a/main.cpp b/main.cpp index 865b98b..a0e9342 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -15,13 +16,14 @@ extern "C" { #include +#include "clip_list.h" +#include "defs.h" #include "mainwindow.h" #include "ffmpeg_raii.h" +#include "player.h" #include "post_to_main_thread.h" #include "ui_mainwindow.h" -#define MAX_STREAMS 16 - using namespace std; using namespace std::chrono; @@ -38,7 +40,7 @@ string filename_for_frame(unsigned stream_idx, int64_t pts) mutex frame_mu; vector frames[MAX_STREAMS]; -int thread_func(); +int record_thread_func(); int main(int argc, char **argv) { @@ -49,12 +51,13 @@ int main(int argc, char **argv) MainWindow mainWindow; mainWindow.show(); - thread(thread_func).detach(); + thread(record_thread_func).detach(); + start_player_thread(); return app.exec(); } -int thread_func() +int record_thread_func() { auto format_ctx = avformat_open_input_unique("multiangle.mp4", nullptr, nullptr); if (format_ctx == nullptr) { diff --git a/mainwindow.cpp b/mainwindow.cpp index 9db4a9b..bbeeef9 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include "clip_list.h" +#include "player.h" #include "ui_mainwindow.h" #include @@ -12,6 +13,7 @@ using namespace std; MainWindow *global_mainwindow = nullptr; extern int64_t current_pts; +ClipList *clips; MainWindow::MainWindow() : ui(new Ui::MainWindow) @@ -19,13 +21,13 @@ MainWindow::MainWindow() global_mainwindow = this; ui->setupUi(this); - ClipList *clips = new ClipList; + clips = new ClipList; ui->clip_list->setModel(clips); // TODO: Make these into buttons. // TODO: These are too big for lambdas. QShortcut *cue_in = new QShortcut(QKeySequence(Qt::Key_A), this); - connect(cue_in, &QShortcut::activated, [clips]{ + connect(cue_in, &QShortcut::activated, []{ if (!clips->empty() && clips->back()->pts_out < 0) { clips->back()->pts_in = current_pts; return; @@ -36,7 +38,7 @@ MainWindow::MainWindow() }); QShortcut *cue_out = new QShortcut(QKeySequence(Qt::Key_S), this); - connect(cue_out, &QShortcut::activated, [clips]{ + connect(cue_out, &QShortcut::activated, []{ if (!clips->empty()) { clips->back()->pts_out = current_pts; // TODO: select the row in the clip list? @@ -49,5 +51,5 @@ MainWindow::MainWindow() void MainWindow::preview_clicked() { - printf("preview\n"); + play_clip(*clips->back(), 0); } diff --git a/player.cpp b/player.cpp new file mode 100644 index 0000000..a2c1a93 --- /dev/null +++ b/player.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include + +#include "clip_list.h" +#include "defs.h" +#include "mainwindow.h" +#include "ffmpeg_raii.h" +#include "post_to_main_thread.h" +#include "ui_mainwindow.h" + +using namespace std; +using namespace std::chrono; + +extern mutex frame_mu; +extern vector frames[MAX_STREAMS]; + +struct PlaylistClip { + Clip clip; + unsigned stream_idx; +}; +vector current_cue_playlist; +mutex playlist_mu; + +enum { PAUSED, PLAYING } cue_state = PAUSED; +mutex cue_state_mu; +condition_variable cue_is_playing; +//int cue_playlist_index = -1; +//int64_t cue_playlist_pos = 0; + +int preview_thread_func() +{ + for ( ;; ) { + // Wait until we're supposed to play something. + { + unique_lock lock(cue_state_mu); + cue_is_playing.wait(lock, []{ + return cue_state == PLAYING; + //return current_cue_status.origin != steady_clock::time_point::max(); + }); + } + + PlaylistClip clip; + { + lock_guard lock2(playlist_mu); + clip = current_cue_playlist[0]; + } + steady_clock::time_point origin = steady_clock::now(); + int64_t pts_origin = clip.clip.pts_in; + + int64_t next_pts = pts_origin; + + bool eof = false; + while (!eof) { // TODO: check for abort + // FIXME: assumes a given timebase. + double speed = 0.5; + steady_clock::time_point next_frame_start = + origin + microseconds((next_pts - pts_origin) * int(1000000 / speed) / 12800); + this_thread::sleep_until(next_frame_start); + global_mainwindow->ui->preview_display->setFrame(clip.stream_idx, next_pts); + + // Find the next frame. + { + lock_guard lock2(frame_mu); + auto it = upper_bound(frames[clip.stream_idx].begin(), + frames[clip.stream_idx].end(), + next_pts); + if (it == frames[clip.stream_idx].end()) { + eof = true; + } else { + next_pts = *it; + if (next_pts >= clip.clip.pts_out) { + eof = true; + } + } + } + if (eof) break; + } + + // TODO: advance the playlist and look for the next element. + { + unique_lock lock(cue_state_mu); + cue_state = PAUSED; + } + } +} + +void start_player_thread() +{ + thread(preview_thread_func).detach(); +} + +void play_clip(const Clip &clip, unsigned stream_idx) +{ + { + lock_guard lock(playlist_mu); + current_cue_playlist.clear(); + current_cue_playlist.push_back(PlaylistClip{ clip, stream_idx }); + } + + { + lock_guard lock(cue_state_mu); + cue_state = PLAYING; + cue_is_playing.notify_all(); + } +} diff --git a/player.h b/player.h new file mode 100644 index 0000000..960bc22 --- /dev/null +++ b/player.h @@ -0,0 +1,9 @@ +#ifndef _PLAYER_H +#define _PLAYER_H 1 + +#include "clip_list.h" + +void start_player_thread(); +void play_clip(const Clip &clip, unsigned stream_idx); + +#endif // !defined(_PLAYER_H) diff --git a/ui_mainwindow.ui b/ui_mainwindow.ui index d55e00d..9f8fee7 100644 --- a/ui_mainwindow.ui +++ b/ui_mainwindow.ui @@ -55,7 +55,7 @@ - + @@ -72,7 +72,7 @@ - + -- 2.39.2