You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
Added pausing, rewind, fast forward, and playing (and different speeds). Still a bit buggy and experimental with fast forward and rewinding (due to seek bugs in readers).
This commit is contained in:
@@ -58,6 +58,7 @@ namespace openshot
|
||||
bool repeat; /// Repeat the audio source when finished
|
||||
int size; /// The size of the internal buffer
|
||||
AudioSampleBuffer *buffer; /// The audio sample buffer
|
||||
int speed; /// The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
|
||||
ReaderBase *reader; /// The reader to pull samples from
|
||||
int64 original_frame_number; /// The current frame to read from
|
||||
@@ -70,6 +71,9 @@ namespace openshot
|
||||
/// Get more samples from the reader
|
||||
void GetMoreSamplesFromReader();
|
||||
|
||||
/// Reverse an audio buffer (for backwards audio)
|
||||
juce::AudioSampleBuffer* reverse_buffer(juce::AudioSampleBuffer* buffer);
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Constructor that reads samples from a reader
|
||||
@@ -111,9 +115,26 @@ namespace openshot
|
||||
void setBuffer (AudioSampleBuffer *audio_buffer);
|
||||
|
||||
const ReaderInfo & getReaderInfo() const { return reader->info; }
|
||||
|
||||
/// Return the current frame object
|
||||
tr1::shared_ptr<Frame> getFrame() const { return frame; }
|
||||
int getFramePosition() const { return frame_position; }
|
||||
|
||||
/// Get the estimate frame that is playing at this moment
|
||||
int getEstimatedFrame() const { return int(estimated_frame); }
|
||||
|
||||
/// Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
void setSpeed(int new_speed) { speed = new_speed; }
|
||||
/// Get Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
int getSpeed() const { return speed; }
|
||||
|
||||
/// Set Reader
|
||||
void Reader(ReaderBase *audio_reader) { reader = audio_reader; }
|
||||
/// Get Reader
|
||||
ReaderBase* Reader() const { return reader; }
|
||||
|
||||
/// Seek to a specific frame
|
||||
int Seek(int64 new_position) { frame_number = new_position; }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ namespace openshot
|
||||
/// Display a loading animation
|
||||
virtual void Loading() = 0;
|
||||
|
||||
/// Get the current mode
|
||||
virtual PlaybackMode Mode() = 0;
|
||||
|
||||
/// Play the video
|
||||
virtual void Play() = 0;
|
||||
|
||||
@@ -81,25 +84,25 @@ namespace openshot
|
||||
virtual void Seek(int new_frame) = 0;
|
||||
|
||||
/// Get the Playback speed
|
||||
float Speed();
|
||||
virtual float Speed() = 0;
|
||||
|
||||
/// Set the Playback speed (1.0 = normal speed, <1.0 = slower, >1.0 faster)
|
||||
void Speed(float new_speed);
|
||||
virtual void Speed(float new_speed) = 0;
|
||||
|
||||
/// Stop the video player and clear the cached frames
|
||||
virtual void Stop() = 0;
|
||||
|
||||
/// Get the current reader, such as a FFmpegReader
|
||||
ReaderBase* Reader();
|
||||
virtual ReaderBase* Reader() = 0;
|
||||
|
||||
/// Set the current reader, such as a FFmpegReader
|
||||
void Reader(ReaderBase *new_reader);
|
||||
virtual void Reader(ReaderBase *new_reader) = 0;
|
||||
|
||||
/// Get the Volume
|
||||
float Volume();
|
||||
virtual float Volume() = 0;
|
||||
|
||||
/// Set the Volume (1.0 = normal volume, <1.0 = quieter, >1.0 louder)
|
||||
void Volume(float new_volume);
|
||||
virtual void Volume(float new_volume) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <QtWidgets/QBoxLayout>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtGui/qevent.h>
|
||||
|
||||
namespace openshot
|
||||
{
|
||||
@@ -26,6 +27,9 @@ public:
|
||||
PlayerDemo(QWidget *parent = 0);
|
||||
~PlayerDemo();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
|
||||
private slots:
|
||||
void open(bool checked);
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace openshot
|
||||
class QtPlayer : public PlayerBase
|
||||
{
|
||||
PlayerPrivate *p;
|
||||
bool threads_started;
|
||||
|
||||
public:
|
||||
/// Default constructor
|
||||
@@ -64,6 +65,9 @@ namespace openshot
|
||||
/// Display a loading animation
|
||||
void Loading();
|
||||
|
||||
/// Get the current mode
|
||||
PlaybackMode Mode();
|
||||
|
||||
/// Pause the video
|
||||
void Pause();
|
||||
|
||||
@@ -73,8 +77,26 @@ namespace openshot
|
||||
/// Seek to a specific frame in the player
|
||||
void Seek(int new_frame);
|
||||
|
||||
/// Get the Playback speed
|
||||
float Speed();
|
||||
|
||||
/// Set the Playback speed (1.0 = normal speed, <1.0 = slower, >1.0 faster)
|
||||
void Speed(float new_speed);
|
||||
|
||||
/// Stop the video player and clear the cached frames
|
||||
void Stop();
|
||||
|
||||
/// Set the current reader
|
||||
void Reader(ReaderBase *new_reader);
|
||||
|
||||
/// Get the current reader, such as a FFmpegReader
|
||||
ReaderBase* Reader();
|
||||
|
||||
/// Get the Volume
|
||||
float Volume();
|
||||
|
||||
/// Set the Volume (1.0 = normal volume, <1.0 = quieter, >1.0 louder)
|
||||
void Volume(float new_volume);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ using namespace openshot;
|
||||
// Constructor that reads samples from a reader
|
||||
AudioReaderSource::AudioReaderSource(ReaderBase *audio_reader, int64 starting_frame_number, int buffer_size)
|
||||
: reader(audio_reader), frame_number(starting_frame_number), original_frame_number(starting_frame_number),
|
||||
size(buffer_size), position(0), frame_position(0), estimated_frame(0) {
|
||||
size(buffer_size), position(0), frame_position(0), estimated_frame(0), speed(1) {
|
||||
|
||||
// Initialize an audio buffer (based on reader)
|
||||
buffer = new juce::AudioSampleBuffer(reader->info.channels, size);
|
||||
@@ -79,13 +79,14 @@ void AudioReaderSource::GetMoreSamplesFromReader() {
|
||||
position = 0;
|
||||
|
||||
// Loop through frames until buffer filled
|
||||
while (amount_needed > 0) {
|
||||
while (amount_needed > 0 && speed != 0) {
|
||||
|
||||
// Get the next frame (if position is zero)
|
||||
if (frame_position == 0) {
|
||||
try {
|
||||
// Get frame object
|
||||
frame = reader->GetFrameSafe(frame_number++);
|
||||
frame = reader->GetFrameSafe(frame_number);
|
||||
frame_number = frame_number + speed;
|
||||
|
||||
} catch (const ReaderClosed & e) {
|
||||
break;
|
||||
@@ -110,7 +111,12 @@ void AudioReaderSource::GetMoreSamplesFromReader() {
|
||||
|
||||
// Load all of its samples into the buffer
|
||||
for (int channel = 0; channel < new_buffer->getNumChannels(); channel++)
|
||||
new_buffer->addFrom(channel, position, *frame->GetAudioSampleBuffer(), channel, frame_position, amount_to_copy);
|
||||
if (speed >= 0)
|
||||
// playback normal
|
||||
new_buffer->addFrom(channel, position, *frame->GetAudioSampleBuffer(), channel, frame_position, amount_to_copy);
|
||||
else
|
||||
// reverse playback
|
||||
new_buffer->addFrom(channel, position, *reverse_buffer(frame->GetAudioSampleBuffer()), channel, frame_position, amount_to_copy);
|
||||
|
||||
// Adjust remaining samples
|
||||
position += amount_to_copy;
|
||||
@@ -131,6 +137,37 @@ void AudioReaderSource::GetMoreSamplesFromReader() {
|
||||
position = 0;
|
||||
}
|
||||
|
||||
// Reverse an audio buffer
|
||||
juce::AudioSampleBuffer* AudioReaderSource::reverse_buffer(juce::AudioSampleBuffer* buffer)
|
||||
{
|
||||
int number_of_samples = buffer->getNumSamples();
|
||||
int channels = buffer->getNumChannels();
|
||||
|
||||
// Reverse array (create new buffer to hold the reversed version)
|
||||
AudioSampleBuffer *reversed = new juce::AudioSampleBuffer(channels, number_of_samples);
|
||||
reversed->clear();
|
||||
|
||||
for (int channel = 0; channel < channels; channel++)
|
||||
{
|
||||
int n=0;
|
||||
for (int s = number_of_samples - 1; s >= 0; s--, n++)
|
||||
reversed->getSampleData(channel)[n] = buffer->getSampleData(channel)[s];
|
||||
}
|
||||
|
||||
// Copy the samples back to the original array
|
||||
buffer->clear();
|
||||
// Loop through channels, and get audio samples
|
||||
for (int channel = 0; channel < channels; channel++)
|
||||
// Get the audio samples for this channel
|
||||
buffer->addFrom(channel, 0, reversed->getSampleData(channel), number_of_samples, 1.0f);
|
||||
|
||||
delete reversed;
|
||||
reversed = NULL;
|
||||
|
||||
// return pointer or passed in object (so this method can be chained together)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Get the next block of audio samples
|
||||
void AudioReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
|
||||
{
|
||||
@@ -182,7 +219,8 @@ void AudioReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
|
||||
|
||||
// Adjust estimate frame number (the estimated frame number that is being played)
|
||||
estimated_samples_per_frame = Frame::GetSamplesPerFrame(estimated_frame, reader->info.fps, reader->info.sample_rate);
|
||||
estimated_frame += double(info.numSamples) / double(estimated_samples_per_frame);
|
||||
if (speed != 0)
|
||||
estimated_frame += double(info.numSamples) / double(estimated_samples_per_frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* @file
|
||||
* @brief Source file for AudioPlaybackThread class
|
||||
* @author Duzy Chan <code@duzy.info>
|
||||
* @author Jonathan Thomas <jonathan@openshot.org> *
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
@@ -44,6 +45,7 @@ namespace openshot
|
||||
}
|
||||
};
|
||||
|
||||
// Construtor
|
||||
AudioPlaybackThread::AudioPlaybackThread()
|
||||
: Thread("audio-playback")
|
||||
, audioDeviceManager()
|
||||
@@ -57,28 +59,41 @@ namespace openshot
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor
|
||||
AudioPlaybackThread::~AudioPlaybackThread()
|
||||
{
|
||||
}
|
||||
|
||||
void AudioPlaybackThread::setReader(ReaderBase *reader)
|
||||
// Set the reader object
|
||||
void AudioPlaybackThread::Reader(ReaderBase *reader)
|
||||
{
|
||||
sampleRate = reader->info.sample_rate;
|
||||
numChannels = reader->info.channels;
|
||||
source = new AudioReaderSource(reader, 1, buffer_size);
|
||||
if (!source) {
|
||||
sampleRate = reader->info.sample_rate;
|
||||
numChannels = reader->info.channels;
|
||||
source = new AudioReaderSource(reader, 1, buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the current frame object (which is filling the buffer)
|
||||
tr1::shared_ptr<Frame> AudioPlaybackThread::getFrame()
|
||||
{
|
||||
if (source) return source->getFrame();
|
||||
return tr1::shared_ptr<Frame>();
|
||||
}
|
||||
|
||||
// Get the currently playing frame number
|
||||
int AudioPlaybackThread::getCurrentFramePosition()
|
||||
{
|
||||
return source ? source->getEstimatedFrame() : 0;
|
||||
}
|
||||
|
||||
// Seek the audio thread
|
||||
void AudioPlaybackThread::Seek(int new_position)
|
||||
{
|
||||
source->Seek(new_position);
|
||||
}
|
||||
|
||||
// Start audio thread
|
||||
void AudioPlaybackThread::run()
|
||||
{
|
||||
// Init audio device
|
||||
@@ -113,7 +128,7 @@ namespace openshot
|
||||
transport.start();
|
||||
|
||||
while (!threadShouldExit() && transport.isPlaying()) {
|
||||
sleep(1);
|
||||
sleep(100);
|
||||
}
|
||||
|
||||
transport.stop();
|
||||
@@ -124,5 +139,9 @@ namespace openshot
|
||||
audioDeviceManager.closeAudioDevice();
|
||||
audioDeviceManager.removeAllChangeListeners();
|
||||
audioDeviceManager.dispatchPendingMessages();
|
||||
|
||||
// Remove source
|
||||
delete source;
|
||||
source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* @file
|
||||
* @brief Source file for AudioPlaybackThread class
|
||||
* @author Duzy Chan <code@duzy.info>
|
||||
* @author Jonathan Thomas <jonathan@openshot.org>
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
@@ -31,7 +32,7 @@ namespace openshot
|
||||
using juce::WaitableEvent;
|
||||
|
||||
/**
|
||||
* @brief The audio playback class.
|
||||
* @brief The audio playback thread
|
||||
*/
|
||||
class AudioPlaybackThread : Thread
|
||||
{
|
||||
@@ -47,15 +48,32 @@ namespace openshot
|
||||
WaitableEvent played;
|
||||
int buffer_size;
|
||||
|
||||
/// Constructor
|
||||
AudioPlaybackThread();
|
||||
/// Destructor
|
||||
~AudioPlaybackThread();
|
||||
|
||||
void setReader(ReaderBase *reader);
|
||||
/// Set the current thread's reader
|
||||
void Reader(ReaderBase *reader);
|
||||
|
||||
/// Get the current frame object (which is filling the buffer)
|
||||
tr1::shared_ptr<Frame> getFrame();
|
||||
|
||||
/// Get the current frame number being played
|
||||
int getCurrentFramePosition();
|
||||
|
||||
/// Seek the audio thread
|
||||
void Seek(int new_position);
|
||||
|
||||
/// Start thread
|
||||
void run();
|
||||
|
||||
/// Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
void setSpeed(int new_speed) { if (source) source->setSpeed(new_speed); }
|
||||
|
||||
/// Get Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
int getSpeed() const { if (source) return source->getSpeed(); else return 1; }
|
||||
|
||||
friend class PlayerPrivate;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* @file player.cpp
|
||||
*/
|
||||
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "../../../include/QtPlayer.h"
|
||||
#include "../../../include/Qt/PlayerDemo.h"
|
||||
#include "../../../include/Qt/VideoRenderWidget.h"
|
||||
@@ -30,6 +32,10 @@ PlayerDemo::PlayerDemo(QWidget *parent)
|
||||
vbox->setMargin(0);
|
||||
vbox->setSpacing(0);
|
||||
resize(600, 480);
|
||||
|
||||
// Accept keyboard event
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
}
|
||||
|
||||
PlayerDemo::~PlayerDemo()
|
||||
@@ -37,6 +43,42 @@ PlayerDemo::~PlayerDemo()
|
||||
delete player;
|
||||
}
|
||||
|
||||
void PlayerDemo::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
string key = event->text().toStdString();
|
||||
if (key == " ") {
|
||||
cout << "START / STOP: " << player->Mode() << endl;
|
||||
if (player->Mode() == openshot::PLAYBACK_PLAY)
|
||||
player->Pause();
|
||||
else if (player->Mode() == openshot::PLAYBACK_PAUSED)
|
||||
player->Play();
|
||||
|
||||
}
|
||||
else if (key == "j") {
|
||||
cout << "BACKWARD" << player->Speed() - 1 << endl;
|
||||
int current_speed = player->Speed();
|
||||
player->Speed(current_speed - 1); // backwards
|
||||
|
||||
}
|
||||
else if (key == "k") {
|
||||
cout << "PAUSE" << endl;
|
||||
if (player->Mode() == openshot::PLAYBACK_PLAY)
|
||||
player->Pause();
|
||||
else if (player->Mode() == openshot::PLAYBACK_PAUSED)
|
||||
player->Play();
|
||||
|
||||
}
|
||||
else if (key == "l") {
|
||||
cout << "FORWARD" << player->Speed() + 1 << endl;
|
||||
int current_speed = player->Speed();
|
||||
player->Speed(current_speed + 1); // backwards
|
||||
|
||||
}
|
||||
|
||||
event->accept();
|
||||
QWidget::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void PlayerDemo::open(bool checked)
|
||||
{
|
||||
const QString filename = QFileDialog::getOpenFileName(this, "Open Video File");
|
||||
|
||||
@@ -25,22 +25,20 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "../include/ReaderBase.h"
|
||||
#include "../include/RendererBase.h"
|
||||
#include "../include/AudioReaderSource.h"
|
||||
|
||||
#include "PlayerPrivate.h"
|
||||
#include "AudioPlaybackThread.h"
|
||||
#include "VideoPlaybackThread.h"
|
||||
|
||||
namespace openshot
|
||||
{
|
||||
// Constructor
|
||||
PlayerPrivate::PlayerPrivate(RendererBase *rb)
|
||||
: Thread("player"), video_position(0), audio_position(0)
|
||||
, audioPlayback(new AudioPlaybackThread())
|
||||
, videoPlayback(new VideoPlaybackThread(rb))
|
||||
{
|
||||
}
|
||||
, speed(1), reader(NULL)
|
||||
{ }
|
||||
|
||||
// Destructor
|
||||
PlayerPrivate::~PlayerPrivate()
|
||||
{
|
||||
if (isThreadRunning()) stopThread(500);
|
||||
@@ -50,13 +48,15 @@ namespace openshot
|
||||
delete videoPlayback;
|
||||
}
|
||||
|
||||
// Start thread
|
||||
void PlayerPrivate::run()
|
||||
{
|
||||
// Kill audio and video threads (if they are currently running)
|
||||
if (audioPlayback->isThreadRunning() && reader->info.has_audio) audioPlayback->stopThread(-1);
|
||||
if (videoPlayback->isThreadRunning() && reader->info.has_video) videoPlayback->stopThread(-1);
|
||||
|
||||
// Set the reader for the Audio thread
|
||||
audioPlayback->setReader(reader);
|
||||
audioPlayback->Reader(reader);
|
||||
|
||||
// Start the threads
|
||||
if (reader->info.has_audio)
|
||||
@@ -67,6 +67,15 @@ namespace openshot
|
||||
tr1::shared_ptr<Frame> frame;
|
||||
while (!threadShouldExit()) {
|
||||
|
||||
// Calculate the milliseconds a single frame should stay on the screen
|
||||
double frame_time = (1000.0 / reader->info.fps.ToDouble());
|
||||
|
||||
// Experimental Pausing Code
|
||||
if (speed == 0) {
|
||||
sleep(frame_time);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the start time (to track how long a frame takes to render)
|
||||
const Time t1 = Time::getCurrentTime();
|
||||
|
||||
@@ -88,9 +97,6 @@ namespace openshot
|
||||
// Get the end time (to track how long a frame takes to render)
|
||||
const Time t2 = Time::getCurrentTime();
|
||||
|
||||
// Calculate the milliseconds a single frame should stay on the screen
|
||||
double frame_time = (1000.0 / reader->info.fps.ToDouble());
|
||||
|
||||
// Determine how many milliseconds it took to render the frame
|
||||
int64 render_time = t2.toMilliseconds() - t1.toMilliseconds();
|
||||
|
||||
@@ -112,25 +118,24 @@ namespace openshot
|
||||
// Debug output
|
||||
std::cout << "video frame diff: " << video_frame_diff << std::endl;
|
||||
|
||||
// Determine if the next frame will be the end of stream
|
||||
//if ((video_position + 1) > reader->info.video_length)
|
||||
//{
|
||||
// End threads at END OF STREAM
|
||||
//if (reader->info.has_audio)
|
||||
// audioPlayback->stopThread(1);
|
||||
//if (reader->info.has_video)
|
||||
// videoPlayback->stopThread(2);
|
||||
//}
|
||||
}
|
||||
|
||||
std::cout << "stopped thread" << endl;
|
||||
|
||||
// Kill audio and video threads (if they are still running)
|
||||
if (audioPlayback->isThreadRunning() && reader->info.has_audio) audioPlayback->stopThread(-1);
|
||||
if (videoPlayback->isThreadRunning() && reader->info.has_video) videoPlayback->stopThread(-1);
|
||||
}
|
||||
|
||||
// Get the next displayed frame (based on speed and direction)
|
||||
tr1::shared_ptr<Frame> PlayerPrivate::getFrame()
|
||||
{
|
||||
try {
|
||||
return reader->GetFrameSafe(video_position++);
|
||||
|
||||
// Get the next frame (based on speed)
|
||||
video_position = video_position + speed;
|
||||
return reader->GetFrameSafe(video_position);
|
||||
|
||||
} catch (const ReaderClosed & e) {
|
||||
// ...
|
||||
} catch (const TooManySeeks & e) {
|
||||
@@ -141,6 +146,7 @@ namespace openshot
|
||||
return tr1::shared_ptr<Frame>();
|
||||
}
|
||||
|
||||
// Start video/audio playback
|
||||
bool PlayerPrivate::startPlayback()
|
||||
{
|
||||
if (video_position < 0) return false;
|
||||
@@ -149,9 +155,39 @@ namespace openshot
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stop video/audio playback
|
||||
void PlayerPrivate::stopPlayback(int timeOutMilliseconds)
|
||||
{
|
||||
std::cout << "stop playback!!!" << std::endl;
|
||||
if (isThreadRunning()) stopThread(timeOutMilliseconds);
|
||||
}
|
||||
|
||||
// Seek to a frame
|
||||
void PlayerPrivate::Seek(int new_position)
|
||||
{
|
||||
// Check for seek
|
||||
if (new_position > 0) {
|
||||
// Update current position
|
||||
video_position = new_position;
|
||||
|
||||
// Notify audio thread that seek has occured
|
||||
audioPlayback->Seek(video_position);
|
||||
}
|
||||
}
|
||||
|
||||
// Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
void PlayerPrivate::Speed(int new_speed)
|
||||
{
|
||||
speed = new_speed;
|
||||
if (reader->info.has_audio)
|
||||
audioPlayback->setSpeed(new_speed);
|
||||
}
|
||||
|
||||
// Set the reader object
|
||||
void PlayerPrivate::Reader(ReaderBase *new_reader)
|
||||
{
|
||||
reader = new_reader;
|
||||
audioPlayback->Reader(new_reader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
* along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../include/ReaderBase.h"
|
||||
#include "../include/RendererBase.h"
|
||||
#include "../include/AudioReaderSource.h"
|
||||
#include "AudioPlaybackThread.h"
|
||||
#include "VideoPlaybackThread.h"
|
||||
|
||||
namespace openshot
|
||||
{
|
||||
class AudioPlaybackThread;
|
||||
@@ -33,26 +39,47 @@ namespace openshot
|
||||
using juce::Thread;
|
||||
|
||||
/**
|
||||
* @brief The private part of QtPlayer class.
|
||||
* @brief The private part of QtPlayer class, which contains an audio thread and video thread,
|
||||
* and controls the video timing and audio synchronization code.
|
||||
*/
|
||||
class PlayerPrivate : Thread
|
||||
{
|
||||
int video_position; /// The current frame position.
|
||||
int audio_position; /// The current frame position.
|
||||
ReaderBase *reader;
|
||||
AudioPlaybackThread *audioPlayback;
|
||||
VideoPlaybackThread *videoPlayback;
|
||||
ReaderBase *reader; /// The reader which powers this player
|
||||
AudioPlaybackThread *audioPlayback; /// The audio thread
|
||||
VideoPlaybackThread *videoPlayback; /// The video thread
|
||||
int speed; /// The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
|
||||
/// Constructor
|
||||
PlayerPrivate(RendererBase *rb);
|
||||
/// Destructor
|
||||
virtual ~PlayerPrivate();
|
||||
|
||||
/// Start thread
|
||||
void run();
|
||||
|
||||
/// Seek to a frame
|
||||
void Seek(int new_position);
|
||||
|
||||
/// Start the video/audio playback
|
||||
bool startPlayback();
|
||||
|
||||
/// Stop the video/audio playback
|
||||
void stopPlayback(int timeOutMilliseconds = -1);
|
||||
|
||||
/// Get the next frame (based on speed and direction)
|
||||
tr1::shared_ptr<Frame> getFrame();
|
||||
|
||||
/// Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
void Speed(int new_speed);
|
||||
/// Get Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...)
|
||||
int Speed() const { return speed; }
|
||||
|
||||
/// Set the current reader
|
||||
void Reader(ReaderBase *new_reader);
|
||||
|
||||
/// The parent class of PlayerPrivate
|
||||
friend class QtPlayer;
|
||||
};
|
||||
|
||||
|
||||
@@ -31,16 +31,19 @@
|
||||
|
||||
namespace openshot
|
||||
{
|
||||
// Constructor
|
||||
VideoPlaybackThread::VideoPlaybackThread(RendererBase *rb)
|
||||
: Thread("video-playback"), renderer(rb)
|
||||
, render(), reset(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor
|
||||
VideoPlaybackThread::~VideoPlaybackThread()
|
||||
{
|
||||
}
|
||||
|
||||
// Get the currently playing frame number (if any)
|
||||
int VideoPlaybackThread::getCurrentFramePosition()
|
||||
{
|
||||
if (frame)
|
||||
@@ -49,11 +52,15 @@ namespace openshot
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Start the thread
|
||||
void VideoPlaybackThread::run()
|
||||
{
|
||||
while (!threadShouldExit()) {
|
||||
render.wait();
|
||||
// Make other threads wait on the render event
|
||||
render.wait();
|
||||
// Render the frame to the screen
|
||||
renderer->paint(frame);
|
||||
// Signal to other threads that the rendered event has completed
|
||||
rendered.signal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,18 @@ namespace openshot
|
||||
WaitableEvent rendered;
|
||||
bool reset;
|
||||
|
||||
/// Constructor
|
||||
VideoPlaybackThread(RendererBase *rb);
|
||||
/// Destructor
|
||||
~VideoPlaybackThread();
|
||||
|
||||
/// Get the currently playing frame number (if any)
|
||||
int getCurrentFramePosition();
|
||||
|
||||
/// Start the thread
|
||||
void run();
|
||||
|
||||
/// Parent class of VideoPlaybackThread
|
||||
friend class PlayerPrivate;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,15 +32,15 @@
|
||||
|
||||
using namespace openshot;
|
||||
|
||||
QtPlayer::QtPlayer(RendererBase *rb) : PlayerBase(), p(new PlayerPrivate(rb))
|
||||
QtPlayer::QtPlayer(RendererBase *rb) : PlayerBase(), p(new PlayerPrivate(rb)), threads_started(false)
|
||||
{
|
||||
reader = NULL;
|
||||
reader = NULL;
|
||||
}
|
||||
|
||||
QtPlayer::~QtPlayer()
|
||||
{
|
||||
if (mode != PLAYBACK_STOPPED) {
|
||||
//p->stop();
|
||||
Stop();
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
@@ -49,15 +49,21 @@ void QtPlayer::SetSource(const std::string &source)
|
||||
{
|
||||
reader = new FFmpegReader(source);
|
||||
reader->Open();
|
||||
p->Reader(reader);
|
||||
}
|
||||
|
||||
void QtPlayer::Play()
|
||||
{
|
||||
mode = PLAYBACK_PLAY;
|
||||
p->stopPlayback();
|
||||
p->video_position = 0;
|
||||
p->reader = reader;
|
||||
p->startPlayback();
|
||||
cout << "PLAY() on QTPlayer" << endl;
|
||||
if (reader && !threads_started) {
|
||||
mode = PLAYBACK_PLAY;
|
||||
p->Reader(reader);
|
||||
p->startPlayback();
|
||||
threads_started = true;
|
||||
} else {
|
||||
mode = PLAYBACK_PLAY;
|
||||
Speed(1);
|
||||
}
|
||||
}
|
||||
|
||||
void QtPlayer::Loading()
|
||||
@@ -65,9 +71,16 @@ void QtPlayer::Loading()
|
||||
mode = PLAYBACK_LOADING;
|
||||
}
|
||||
|
||||
/// Get the current mode
|
||||
PlaybackMode QtPlayer::Mode()
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
|
||||
void QtPlayer::Pause()
|
||||
{
|
||||
mode = PLAYBACK_PAUSED;
|
||||
Speed(0);
|
||||
}
|
||||
|
||||
int QtPlayer::Position()
|
||||
@@ -78,10 +91,46 @@ int QtPlayer::Position()
|
||||
void QtPlayer::Seek(int new_frame)
|
||||
{
|
||||
// Seek the reader to a new position
|
||||
p->video_position = new_frame;
|
||||
p->Seek(new_frame);
|
||||
}
|
||||
|
||||
void QtPlayer::Stop()
|
||||
{
|
||||
mode = PLAYBACK_STOPPED;
|
||||
p->stopPlayback();
|
||||
p->video_position = 0;
|
||||
threads_started = false;
|
||||
}
|
||||
|
||||
// Set the reader object
|
||||
void QtPlayer::Reader(ReaderBase *new_reader)
|
||||
{
|
||||
reader = new_reader;
|
||||
p->Reader(new_reader);
|
||||
}
|
||||
|
||||
// Get the current reader, such as a FFmpegReader
|
||||
ReaderBase* QtPlayer::Reader() {
|
||||
return reader;
|
||||
}
|
||||
|
||||
// Get the Playback speed
|
||||
float QtPlayer::Speed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
// Set the Playback speed multiplier (1.0 = normal speed, <1.0 = slower, >1.0 faster)
|
||||
void QtPlayer::Speed(float new_speed) {
|
||||
speed = new_speed;
|
||||
p->Speed(new_speed);
|
||||
}
|
||||
|
||||
// Get the Volume
|
||||
float QtPlayer::Volume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
// Set the Volume multiplier (1.0 = normal volume, <1.0 = quieter, >1.0 louder)
|
||||
void QtPlayer::Volume(float new_volume) {
|
||||
volume = new_volume;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user