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);
Header file for all Exception classes.
Source file for PlayerPrivate class.
The audio playback thread.
This is the base class of all Renderers in libopenshot.
Handles prefetching and caching of video/audio frames for smooth playback.
The video playback class.
This namespace is the default namespace for all code in the openshot library.