/** * @file * @brief Source file for VideoCacheThread class * @author Jonathan Thomas * * @ref License */ /* LICENSE * * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the * world. For more information visit . * * OpenShot Library (libopenshot) is free software: you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * OpenShot Library (libopenshot) is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with OpenShot Library. If not, see . */ #include "VideoCacheThread.h" #include #include // for std::this_thread::sleep_for #include // for std::chrono::milliseconds namespace openshot { // Constructor VideoCacheThread::VideoCacheThread() : Thread("video-cache"), speed(1), is_playing(false), position(1) , reader(NULL), max_frames(std::min(OPEN_MP_NUM_PROCESSORS * 8, 64)), current_display_frame(1) { } // Destructor VideoCacheThread::~VideoCacheThread() { } // Get the currently playing frame number (if any) int64_t VideoCacheThread::getCurrentFramePosition() { if (frame) return frame->number; else return 0; } // Set the currently playing frame number (if any) void VideoCacheThread::setCurrentFramePosition(int64_t current_frame_number) { current_display_frame = current_frame_number; } // Seek the reader to a particular frame number void VideoCacheThread::Seek(int64_t new_position) { position = new_position; } // Play the video void VideoCacheThread::Play() { // Start playing is_playing = true; } // Stop the audio void VideoCacheThread::Stop() { // Stop playing is_playing = false; } // Start the thread void VideoCacheThread::run() { // Types for storing time durations in whole and fractional milliseconds using ms = std::chrono::milliseconds; using double_ms = std::chrono::duration; // Calculate on-screen time for a single frame in milliseconds const auto frame_duration = double_ms(1000.0 / reader->info.fps.ToDouble()); while (!threadShouldExit() && is_playing) { // Cache frames before the other threads need them // Cache frames up to the max frames. Reset to current position // if cache gets too far away from display frame. Cache frames // even when player is paused (i.e. speed 0). while ((position - current_display_frame) < max_frames) { // Only cache up till the max_frames amount... then sleep try { if (reader) { ZmqLogger::Instance()->AppendDebugMethod("VideoCacheThread::run (cache frame)", "position", position, "current_display_frame", current_display_frame, "max_frames", max_frames, "needed_frames", (position - current_display_frame)); // Force the frame to be generated if (reader->GetCache()->GetSmallestFrame()) { int64_t smallest_cached_frame = reader->GetCache()->GetSmallestFrame()->number; if (smallest_cached_frame > current_display_frame) { // Cache position has gotten too far away from current display frame. // Reset the position to the current display frame. position = current_display_frame; } } reader->GetFrame(position); } } catch (const OutOfBoundsFrame & e) { // Ignore out of bounds frame exceptions } // Increment frame number position++; } // Sleep for 1 frame length std::this_thread::sleep_for(frame_duration); } return; } }