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             if ((speed == 0 && video_position == last_video_position) ||
 
   78                 (speed != 0 && last_speed != speed) ||
 
   79                 (speed != 0 && !is_dirty && !videoCache->isReady()))
 
   82                 std::this_thread::sleep_for(frame_duration / 4);
 
   85                 start_time = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now());
 
   90                 audioPlayback->Seek(video_position);
 
   99             videoPlayback->frame = frame;
 
  100             videoPlayback->render.signal();
 
  103             last_video_position = video_position;
 
  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);
 
  112             if (remaining_time > remaining_time.zero() ) {
 
  113                 if (remaining_time < max_sleep) {
 
  114                     std::this_thread::sleep_for(remaining_time);
 
  117                     std::this_thread::sleep_for(max_sleep);
 
  124     std::shared_ptr<openshot::Frame> PlayerPrivate::getFrame()
 
  131         if (video_position + speed >= 1 && video_position + speed <= reader->info.video_length) {
 
  132             video_position = video_position + speed;
 
  134         } 
else if (video_position + speed < 1) {
 
  138         } 
else if (video_position + speed > reader->info.video_length) {
 
  140             video_position = reader->info.video_length;
 
  144         if (frame && frame->number == video_position && video_position == last_video_position) {
 
  151             playback_frames += std::abs(speed);
 
  154             videoCache->Seek(video_position);
 
  157             return reader->GetFrame(video_position);
 
  160     } 
catch (
const ReaderClosed & e) {
 
  162     } 
catch (
const OutOfBoundsFrame & e) {
 
  165     return std::shared_ptr<openshot::Frame>();
 
  169     void PlayerPrivate::Seek(int64_t new_position)
 
  171         video_position = new_position;
 
  172         last_video_position = 0;
 
  177     bool PlayerPrivate::startPlayback()
 
  179         if (video_position < 0) 
return false;
 
  182         startThread(Priority::high);
 
  187     void PlayerPrivate::stopPlayback()
 
  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);