OpenShot Library | libopenshot 0.3.3
Loading...
Searching...
No Matches
PlayerPrivate.cpp
Go to the documentation of this file.
1
10// Copyright (c) 2008-2019 OpenShot Studios, LLC
11//
12// SPDX-License-Identifier: LGPL-3.0-or-later
13
14#include "PlayerPrivate.h"
15#include "Exceptions.h"
16
17#include <queue>
18#include <thread> // for std::this_thread::sleep_for
19#include <chrono> // for std::chrono microseconds, high_resolution_clock
20
21namespace openshot
22{
24 // Constructor
25 PlayerPrivate::PlayerPrivate(openshot::RendererBase *rb)
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)
28 {
29 videoCache = new openshot::VideoCacheThread();
30 audioPlayback = new openshot::AudioPlaybackThread(videoCache);
31 videoPlayback = new openshot::VideoPlaybackThread(rb);
32 }
33
34 // Destructor
35 PlayerPrivate::~PlayerPrivate()
36 {
37 stopPlayback();
38 delete audioPlayback;
39 delete videoCache;
40 delete videoPlayback;
41 }
42
43 // Start thread
44 void PlayerPrivate::run()
45 {
46 // bail if no reader set
47 if (!reader)
48 return;
49
50 // Start the threads
51 if (reader->info.has_audio)
52 audioPlayback->startThread(8);
53 if (reader->info.has_video) {
54 videoCache->startThread(2);
55 videoPlayback->startThread(4);
56 }
57
58 using std::chrono::duration_cast;
59
60 // Types for storing time durations in whole and fractional microseconds
61 using micro_sec = std::chrono::microseconds;
62 using double_micro_sec = std::chrono::duration<double, micro_sec::period>;
63
64 // Init start_time of playback
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());
67
68 while (!threadShouldExit()) {
69 // Calculate on-screen time for a single frame
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;
73
74 // Pausing Code (which re-syncs audio/video times)
75 // - If speed is zero or speed changes
76 // - If pre-roll is not ready (This should allow scrubbing of the timeline without waiting on pre-roll)
77 if ((speed == 0 && video_position == last_video_position) ||
78 (speed != 0 && last_speed != speed) ||
79 (speed != 0 && !is_dirty && !videoCache->isReady()))
80 {
81 // Sleep for a fraction of frame duration
82 std::this_thread::sleep_for(frame_duration / 4);
83
84 // Reset current playback start time
85 start_time = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now());
86 playback_frames = 0;
87 last_speed = speed;
88
89 // Seek audio thread (since audio is also paused)
90 audioPlayback->Seek(video_position);
91
92 continue;
93 }
94
95 // Get the current video frame
96 frame = getFrame();
97
98 // Set the video frame on the video thread and render frame
99 videoPlayback->frame = frame;
100 videoPlayback->render.signal();
101
102 // Keep track of the last displayed frame
103 last_video_position = video_position;
104 last_speed = speed;
105
106 // Calculate the diff between 'now' and the predicted frame end time
107 const auto current_time = std::chrono::system_clock::now();
108 const auto remaining_time = double_micro_sec(start_time +
109 (frame_duration * playback_frames) - current_time);
110
111 // Sleep to display video image on screen
112 if (remaining_time > remaining_time.zero() ) {
113 if (remaining_time < max_sleep) {
114 std::this_thread::sleep_for(remaining_time);
115 } else {
116 // Protect against invalid or too-long sleep times
117 std::this_thread::sleep_for(max_sleep);
118 }
119 }
120 }
121 }
122
123 // Get the next displayed frame (based on speed and direction)
124 std::shared_ptr<openshot::Frame> PlayerPrivate::getFrame()
125 {
126 try {
127 // Getting new frame, so clear this flag
128 is_dirty = false;
129
130 // Get the next frame (based on speed)
131 if (video_position + speed >= 1 && video_position + speed <= reader->info.video_length) {
132 video_position = video_position + speed;
133
134 } else if (video_position + speed < 1) {
135 // Start of reader (prevent negative frame number and pause playback)
136 video_position = 1;
137 speed = 0;
138 } else if (video_position + speed > reader->info.video_length) {
139 // End of reader (prevent negative frame number and pause playback)
140 video_position = reader->info.video_length;
141 speed = 0;
142 }
143
144 if (frame && frame->number == video_position && video_position == last_video_position) {
145 // return cached frame
146 return frame;
147 }
148 else
149 {
150 // Increment playback frames (always in the positive direction)
151 playback_frames += std::abs(speed);
152
153 // Update cache on which frame was retrieved
154 videoCache->Seek(video_position);
155
156 // return frame from reader
157 return reader->GetFrame(video_position);
158 }
159
160 } catch (const ReaderClosed & e) {
161 // ...
162 } catch (const OutOfBoundsFrame & e) {
163 // ...
164 }
165 return std::shared_ptr<openshot::Frame>();
166 }
167
168 // Seek to a new position
169 void PlayerPrivate::Seek(int64_t new_position)
170 {
171 video_position = new_position;
172 last_video_position = 0;
173 is_dirty = true;
174 }
175
176 // Start video/audio playback
177 bool PlayerPrivate::startPlayback()
178 {
179 if (video_position < 0) return false;
180
181 stopPlayback();
182 startThread(1);
183 return true;
184 }
185
186 // Stop video/audio playback
187 void PlayerPrivate::stopPlayback()
188 {
189 if (videoCache->isThreadRunning() && reader->info.has_video) videoCache->stopThread(max_sleep_ms);
190 if (audioPlayback->isThreadRunning() && reader->info.has_audio) audioPlayback->stopThread(max_sleep_ms);
191 if (videoPlayback->isThreadRunning() && reader->info.has_video) videoPlayback->stopThread(max_sleep_ms);
192 if (isThreadRunning()) stopThread(max_sleep_ms);
193 }
194
195}
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.
The video cache class.
The video playback class.
This namespace is the default namespace for all code in the openshot library.
Definition Compressor.h:29