3 #include <condition_variable>
10 #include "clip_list.h"
12 #include "ffmpeg_raii.h"
14 #include "jpeg_frame_view.h"
19 using namespace std::chrono;
21 extern mutex frame_mu;
22 extern vector<int64_t> frames[MAX_STREAMS];
23 extern HTTPD *global_httpd;
25 void Player::thread_func()
28 // Wait until we're supposed to play something.
30 unique_lock<mutex> lock(queue_state_mu);
31 new_clip_changed.wait(lock, [this]{
32 return new_clip_ready && current_clip.pts_in != -1;
34 new_clip_ready = false;
41 lock_guard<mutex> lock(mu);
43 stream_idx = current_stream_idx;
45 steady_clock::time_point origin = steady_clock::now();
46 int64_t pts_origin = clip.pts_in;
48 int64_t next_pts = pts_origin - 1; // Make sure we play the frame at clip.pts_in if it exists.
52 // Find the next frame.
54 lock_guard<mutex> lock(frame_mu);
55 auto it = upper_bound(frames[stream_idx].begin(),
56 frames[stream_idx].end(),
58 if (it == frames[stream_idx].end() || *it >= clip.pts_out) {
64 // FIXME: assumes a given timebase.
66 steady_clock::time_point next_frame_start =
67 origin + microseconds((next_pts - pts_origin) * int(1000000 / speed) / 12800);
69 // Sleep until the next frame start, or until there's a new clip we're supposed to play.
71 unique_lock<mutex> lock(queue_state_mu);
72 new_clip_changed.wait_until(lock, next_frame_start, [this]{
73 return new_clip_ready || override_stream_idx != -1;
75 if (new_clip_ready) break;
76 if (override_stream_idx != -1) {
77 stream_idx = override_stream_idx;
78 override_stream_idx = -1;
83 destination->setFrame(stream_idx, next_pts);
85 // Send the frame to the stream.
86 // FIXME: Vaguely less crazy pts, perhaps.
87 double pts_float = fmod(duration<double>(next_frame_start.time_since_epoch()).count(), 86400.0f);
88 int64_t pts = lrint(pts_float * TIMEBASE);
89 video_stream.schedule_original_frame(pts, stream_idx, next_pts);
93 unique_lock<mutex> lock(queue_state_mu);
96 if (done_callback != nullptr && !aborted) {
102 Player::Player(JPEGFrameView *destination)
103 : destination(destination)
105 video_stream.start();
106 thread(&Player::thread_func, this).detach();
109 void Player::play_clip(const Clip &clip, unsigned stream_idx)
112 lock_guard<mutex> lock(mu);
114 current_stream_idx = stream_idx;
118 lock_guard<mutex> lock(queue_state_mu);
119 new_clip_ready = true;
120 override_stream_idx = -1;
121 new_clip_changed.notify_all();
125 void Player::override_angle(unsigned stream_idx)
127 // Corner case: If a new clip is waiting to be played, change its stream and then we're done.
129 unique_lock<mutex> lock(queue_state_mu);
130 if (new_clip_ready) {
131 lock_guard<mutex> lock2(mu);
132 current_stream_idx = stream_idx;
137 // If we are playing a clip, set override_stream_idx, and the player thread will
138 // pick it up and change its internal index.
140 unique_lock<mutex> lock(queue_state_mu);
142 override_stream_idx = stream_idx;
143 new_clip_changed.notify_all();
147 // OK, so we're standing still, presumably at the end of a clip.
148 // Look at the current pts_out (if it exists), and show the closest
152 lock_guard<mutex> lock(mu);
153 if (current_clip.pts_out < 0) {
156 pts_out = current_clip.pts_out;
159 lock_guard<mutex> lock(frame_mu);
160 auto it = upper_bound(frames[stream_idx].begin(), frames[stream_idx].end(), pts_out);
161 if (it == frames[stream_idx].end()) {
164 destination->setFrame(stream_idx, *it);