26 : renderer(rb), Thread(
"player"), video_position(1), audio_position(0),
27 speed(1), reader(NULL), last_video_position(1), max_sleep_ms(125000), playback_frames(0), is_dirty(true)
35 PlayerPrivate::~PlayerPrivate()
44 void PlayerPrivate::run()
51 if (reader->info.has_audio)
52 audioPlayback->startThread(Priority::high);
53 if (reader->info.has_video) {
54 videoCache->startThread(Priority::high);
55 videoPlayback->startThread(Priority::high);
58 using std::chrono::duration_cast;
61 using micro_sec = std::chrono::microseconds;
62 using double_micro_sec = std::chrono::duration<double, micro_sec::period>;
65 std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds> start_time;
66 start_time = std::chrono::time_point_cast<micro_sec>(std::chrono::system_clock::now());
68 while (!threadShouldExit()) {
70 int frame_speed = std::max(abs(speed), 1);
71 const auto frame_duration = double_micro_sec(1000000.0 / (reader->info.fps.ToDouble() * frame_speed));
72 const auto max_sleep = frame_duration * 4;
77 bool wait_paused_hold = (speed == 0 && video_position == last_video_position);
78 bool wait_speed_change = (speed != 0 && last_speed != speed);
79 bool cache_ready = videoCache->isReady();
80 bool wait_preroll = (speed != 0 && !is_dirty && !cache_ready);
81 bool should_wait = (wait_paused_hold || wait_speed_change || wait_preroll);
86 std::this_thread::sleep_for(frame_duration / 4);
89 start_time = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now());
94 audioPlayback->Seek(video_position);
103 videoPlayback->frame = frame;
104 videoPlayback->rendered.reset();
105 videoPlayback->render.signal();
109 const int render_wait_ms = std::max(
111 static_cast<int>(frame_duration.count() / 1000.0 * 2.0)
113 videoPlayback->rendered.wait(render_wait_ms);
116 last_video_position = video_position;
120 const auto current_time = std::chrono::system_clock::now();
121 const auto remaining_time = double_micro_sec(start_time +
122 (frame_duration * playback_frames) - current_time);
125 if (remaining_time > remaining_time.zero() ) {
126 if (remaining_time < max_sleep) {
127 std::this_thread::sleep_for(remaining_time);
130 std::this_thread::sleep_for(max_sleep);
136 start_time = std::chrono::time_point_cast<micro_sec>(current_time);
143 std::shared_ptr<openshot::Frame> PlayerPrivate::getFrame()
150 if (video_position + speed >= 1 && video_position + speed <= reader->info.video_length) {
151 video_position = video_position + speed;
153 }
else if (video_position + speed < 1) {
157 }
else if (video_position + speed > reader->info.video_length) {
159 video_position = reader->info.video_length;
163 if (frame && frame->number == video_position && video_position == last_video_position) {
170 playback_frames += std::abs(speed);
173 videoCache->NotifyPlaybackPosition(video_position);
176 return reader->GetFrame(video_position);
179 }
catch (
const ReaderClosed & e) {
181 }
catch (
const OutOfBoundsFrame & e) {
184 return std::shared_ptr<openshot::Frame>();
188 void PlayerPrivate::Seek(int64_t new_position)
190 video_position = new_position;
191 last_video_position = 0;
200 bool PlayerPrivate::startPlayback()
202 if (video_position < 0)
return false;
205 startThread(Priority::high);
210 void PlayerPrivate::stopPlayback()
212 if (videoCache->isThreadRunning() && reader->info.has_video) videoCache->stopThread(max_sleep_ms);
213 if (audioPlayback->isThreadRunning() && reader->info.has_audio) audioPlayback->stopThread(max_sleep_ms);
214 if (videoPlayback->isThreadRunning() && reader->info.has_video) videoPlayback->stopThread(max_sleep_ms);
215 if (isThreadRunning()) stopThread(max_sleep_ms);