2013-09-12 17:52:10 -05:00
|
|
|
/**
|
|
|
|
|
* @file
|
2013-11-06 23:17:35 -06:00
|
|
|
* @brief Source file for QtPlayer class
|
2014-01-25 03:38:38 +08:00
|
|
|
* @author Duzy Chan <code@duzy.info>
|
2014-03-21 01:25:17 -05:00
|
|
|
* @author Jonathan Thomas <jonathan@openshot.org>
|
2013-09-12 17:52:10 -05:00
|
|
|
*
|
2019-06-09 08:31:04 -04:00
|
|
|
* @ref License
|
|
|
|
|
*/
|
|
|
|
|
|
2021-10-16 01:26:26 -04:00
|
|
|
// Copyright (c) 2008-2019 OpenShot Studios, LLC
|
|
|
|
|
//
|
|
|
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
2013-09-12 17:52:10 -05:00
|
|
|
|
Audio: New device name lookup
- A new AudioDevices class replaces the AudioDeviceInfo struct.
It has a single method, getNames(), which:
* creates an AudioDeviceManager (NOT using the singleton)
* scans for available devices
* returns the results as a std::vector containing
std::pair<std::string, std::string> objects
(The AudioDevices device manager is never initialize()d, so
no devices are opened; it should be safe to use even DURING
playback, without disruption.)
By using STL containers (rather than a custom struct) to return
the results, Python is able to consume the output as a native
list of tuples.
AudioDeviceInfo is still present for compatibility, but deprecated.
- Eliminated some unnecessary conversions (like):
* calls to std::string::c_str, when passing to juce::String.
juce::String accepts std::string directly.
* calls to juce::String::toRawUTF8, when creating std::string.
There's a juce::String::ToStdString, which is better.
2021-08-24 13:03:46 -04:00
|
|
|
#include "QtPlayer.h"
|
|
|
|
|
|
|
|
|
|
#include "AudioDevices.h"
|
2020-10-18 07:43:37 -04:00
|
|
|
#include "Clip.h"
|
|
|
|
|
#include "FFmpegReader.h"
|
|
|
|
|
#include "Timeline.h"
|
|
|
|
|
#include "Qt/PlayerPrivate.h"
|
|
|
|
|
#include "Qt/VideoRenderer.h"
|
2011-10-11 08:44:27 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
namespace openshot
|
2014-03-30 23:21:30 -05:00
|
|
|
{
|
Audio: New device name lookup
- A new AudioDevices class replaces the AudioDeviceInfo struct.
It has a single method, getNames(), which:
* creates an AudioDeviceManager (NOT using the singleton)
* scans for available devices
* returns the results as a std::vector containing
std::pair<std::string, std::string> objects
(The AudioDevices device manager is never initialize()d, so
no devices are opened; it should be safe to use even DURING
playback, without disruption.)
By using STL containers (rather than a custom struct) to return
the results, Python is able to consume the output as a native
list of tuples.
AudioDeviceInfo is still present for compatibility, but deprecated.
- Eliminated some unnecessary conversions (like):
* calls to std::string::c_str, when passing to juce::String.
juce::String accepts std::string directly.
* calls to juce::String::toRawUTF8, when creating std::string.
There's a juce::String::ToStdString, which is better.
2021-08-24 13:03:46 -04:00
|
|
|
|
|
|
|
|
using AudioDeviceList = std::vector<std::pair<std::string, std::string>>;
|
|
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Delegating constructor
|
|
|
|
|
QtPlayer::QtPlayer()
|
|
|
|
|
: QtPlayer::QtPlayer(new VideoRenderer())
|
|
|
|
|
{ }
|
2014-03-30 23:21:30 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Constructor
|
|
|
|
|
QtPlayer::QtPlayer(openshot::RendererBase *rb)
|
|
|
|
|
: PlayerBase()
|
|
|
|
|
, p(new openshot::PlayerPrivate(rb))
|
|
|
|
|
, threads_started(false)
|
|
|
|
|
{
|
|
|
|
|
reader = NULL;
|
|
|
|
|
}
|
2011-10-11 08:44:27 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
QtPlayer::~QtPlayer()
|
|
|
|
|
{
|
|
|
|
|
if (mode != PLAYBACK_STOPPED)
|
|
|
|
|
Stop();
|
2017-03-21 14:38:42 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
delete p;
|
|
|
|
|
}
|
2011-10-11 08:44:27 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
void QtPlayer::CloseAudioDevice()
|
|
|
|
|
{
|
|
|
|
|
// Close audio device (only do this once, when all audio playback is finished)
|
|
|
|
|
openshot::AudioDeviceManagerSingleton::Instance()->CloseAudioDevice();
|
|
|
|
|
}
|
2017-03-26 23:51:03 -07:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Return any error string during initialization
|
|
|
|
|
std::string QtPlayer::GetError() {
|
|
|
|
|
if (reader && threads_started) {
|
|
|
|
|
return p->audioPlayback->getError();
|
|
|
|
|
} else {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-04 00:55:47 -05:00
|
|
|
|
2022-02-11 14:12:25 -06:00
|
|
|
// Return the default audio sample rate (from the system)
|
|
|
|
|
double QtPlayer::GetDefaultSampleRate() {
|
|
|
|
|
if (reader && threads_started) {
|
|
|
|
|
return p->audioPlayback->getDefaultSampleRate();
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
/// Get Audio Devices from JUCE
|
Audio: New device name lookup
- A new AudioDevices class replaces the AudioDeviceInfo struct.
It has a single method, getNames(), which:
* creates an AudioDeviceManager (NOT using the singleton)
* scans for available devices
* returns the results as a std::vector containing
std::pair<std::string, std::string> objects
(The AudioDevices device manager is never initialize()d, so
no devices are opened; it should be safe to use even DURING
playback, without disruption.)
By using STL containers (rather than a custom struct) to return
the results, Python is able to consume the output as a native
list of tuples.
AudioDeviceInfo is still present for compatibility, but deprecated.
- Eliminated some unnecessary conversions (like):
* calls to std::string::c_str, when passing to juce::String.
juce::String accepts std::string directly.
* calls to juce::String::toRawUTF8, when creating std::string.
There's a juce::String::ToStdString, which is better.
2021-08-24 13:03:46 -04:00
|
|
|
AudioDeviceList QtPlayer::GetAudioDeviceNames() {
|
|
|
|
|
AudioDevices devs;
|
|
|
|
|
return devs.getNames();
|
2019-09-21 00:14:32 -04:00
|
|
|
}
|
2019-04-23 16:45:02 -05:00
|
|
|
|
2022-01-26 15:12:15 -06:00
|
|
|
// Set the source JSON of an openshot::Timelime
|
|
|
|
|
void QtPlayer::SetTimelineSource(const std::string &json) {
|
|
|
|
|
// Create timeline instance (720p, since we have no re-scaling in this player yet)
|
|
|
|
|
reader = new Timeline(1280, 720, openshot::Fraction(30, 1), 44100, 2, openshot::LAYOUT_STEREO);
|
|
|
|
|
|
|
|
|
|
Timeline* tm = (Timeline*)reader;
|
|
|
|
|
tm->SetJson(json);
|
|
|
|
|
tm->DisplayInfo();
|
|
|
|
|
tm->Open();
|
|
|
|
|
|
|
|
|
|
// Set the reader
|
|
|
|
|
Reader(reader);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
void QtPlayer::SetSource(const std::string &source)
|
|
|
|
|
{
|
|
|
|
|
FFmpegReader *ffreader = new FFmpegReader(source);
|
|
|
|
|
ffreader->DisplayInfo();
|
2016-01-05 01:59:50 -06:00
|
|
|
|
2021-02-04 17:28:07 -06:00
|
|
|
// Use default sample rate (or use the FFmpegReader's audio settings if any)
|
|
|
|
|
int sample_rate = 44100;
|
|
|
|
|
if (ffreader->info.sample_rate > 0)
|
|
|
|
|
sample_rate = ffreader->info.sample_rate;
|
|
|
|
|
|
|
|
|
|
// Use default channels (or use the FFmpegReader's audio settings if any)
|
|
|
|
|
int channels = 2;
|
|
|
|
|
if (ffreader->info.channels > 0)
|
|
|
|
|
channels = ffreader->info.channels;
|
|
|
|
|
|
|
|
|
|
// Use default channel layout (or use the FFmpegReader's audio settings if any)
|
|
|
|
|
openshot::ChannelLayout channel_layout = openshot::LAYOUT_STEREO;
|
|
|
|
|
if (channels != 2)
|
|
|
|
|
channel_layout = ffreader->info.channel_layout;
|
|
|
|
|
|
|
|
|
|
// Create timeline instance (720p, since we have no re-scaling in this player yet)
|
|
|
|
|
reader = new Timeline(1280, 720, ffreader->info.fps, sample_rate, channels, channel_layout);
|
2019-09-21 00:14:32 -04:00
|
|
|
Clip *c = new Clip(source);
|
2016-01-05 01:59:50 -06:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
Timeline* tm = (Timeline*)reader;
|
|
|
|
|
tm->AddClip(c);
|
|
|
|
|
tm->Open();
|
2015-06-01 00:20:14 -07:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Set the reader
|
|
|
|
|
Reader(reader);
|
|
|
|
|
}
|
2011-10-11 08:44:27 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
void QtPlayer::Play()
|
|
|
|
|
{
|
2021-06-25 15:57:52 -05:00
|
|
|
// Set mode to playing, and speed to normal
|
2019-09-21 00:14:32 -04:00
|
|
|
mode = PLAYBACK_PLAY;
|
|
|
|
|
Speed(1);
|
2015-02-04 23:56:43 -06:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
if (reader && !threads_started) {
|
|
|
|
|
// Start thread only once
|
|
|
|
|
p->startPlayback();
|
|
|
|
|
threads_started = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-01-25 03:38:38 +08:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
void QtPlayer::Loading()
|
|
|
|
|
{
|
|
|
|
|
mode = PLAYBACK_LOADING;
|
|
|
|
|
}
|
2014-01-25 03:38:38 +08:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
/// Get the current mode
|
|
|
|
|
openshot::PlaybackMode QtPlayer::Mode()
|
|
|
|
|
{
|
|
|
|
|
return mode;
|
|
|
|
|
}
|
2014-03-23 01:12:29 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
void QtPlayer::Pause()
|
|
|
|
|
{
|
|
|
|
|
mode = PLAYBACK_PAUSED;
|
|
|
|
|
Speed(0);
|
|
|
|
|
}
|
2014-01-25 03:38:38 +08:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
int64_t QtPlayer::Position()
|
|
|
|
|
{
|
|
|
|
|
return p->video_position;
|
|
|
|
|
}
|
2014-01-25 03:38:38 +08:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
void QtPlayer::Seek(int64_t new_frame)
|
|
|
|
|
{
|
|
|
|
|
// Check for seek
|
|
|
|
|
if (reader && threads_started && new_frame > 0) {
|
|
|
|
|
// Notify cache thread that seek has occurred
|
2022-01-26 17:56:33 -06:00
|
|
|
p->videoCache->Seek(new_frame, true);
|
2015-06-01 00:20:14 -07:00
|
|
|
|
2022-01-26 15:12:15 -06:00
|
|
|
// Notify audio thread that seek has occurred
|
|
|
|
|
p->audioPlayback->Seek(new_frame);
|
|
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Update current position
|
2022-01-26 15:12:15 -06:00
|
|
|
p->Seek(new_frame);
|
2019-09-21 00:14:32 -04:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-25 03:38:38 +08:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
void QtPlayer::Stop()
|
|
|
|
|
{
|
|
|
|
|
// Change mode to stopped
|
|
|
|
|
mode = PLAYBACK_STOPPED;
|
2015-12-04 01:10:40 -06:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Notify threads of stopping
|
|
|
|
|
if (reader && threads_started) {
|
|
|
|
|
p->videoCache->Stop();
|
|
|
|
|
p->audioPlayback->Stop();
|
2015-12-04 01:10:40 -06:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Kill all threads
|
|
|
|
|
p->stopPlayback();
|
|
|
|
|
}
|
2015-12-04 01:10:40 -06:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
p->video_position = 0;
|
|
|
|
|
threads_started = false;
|
|
|
|
|
}
|
2014-03-23 01:12:29 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Set the reader object
|
|
|
|
|
void QtPlayer::Reader(openshot::ReaderBase *new_reader)
|
|
|
|
|
{
|
|
|
|
|
// Set new reader. Note: Be sure to close and dispose of the old reader after calling this
|
|
|
|
|
reader = new_reader;
|
|
|
|
|
p->reader = new_reader;
|
|
|
|
|
p->videoCache->Reader(new_reader);
|
|
|
|
|
p->audioPlayback->Reader(new_reader);
|
|
|
|
|
}
|
2014-03-23 01:12:29 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Get the current reader, such as a FFmpegReader
|
|
|
|
|
openshot::ReaderBase* QtPlayer::Reader() {
|
|
|
|
|
return reader;
|
|
|
|
|
}
|
2014-03-23 01:12:29 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Set the QWidget pointer to display the video on (as a LONG pointer id)
|
|
|
|
|
void QtPlayer::SetQWidget(int64_t qwidget_address) {
|
|
|
|
|
// Update override QWidget address on the video renderer
|
|
|
|
|
p->renderer->OverrideWidget(qwidget_address);
|
|
|
|
|
}
|
2014-03-30 23:21:30 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Get the Renderer pointer address (for Python to cast back into a QObject)
|
|
|
|
|
int64_t QtPlayer::GetRendererQObject() {
|
|
|
|
|
return (int64_t)(VideoRenderer*)p->renderer;
|
|
|
|
|
}
|
2014-04-02 16:48:27 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Get the Playback speed
|
|
|
|
|
float QtPlayer::Speed() {
|
|
|
|
|
return speed;
|
|
|
|
|
}
|
2014-03-23 01:12:29 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// 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;
|
|
|
|
|
p->videoCache->setSpeed(new_speed);
|
|
|
|
|
if (p->reader->info.has_audio)
|
|
|
|
|
p->audioPlayback->setSpeed(new_speed);
|
|
|
|
|
}
|
2014-03-23 01:12:29 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Get the Volume
|
|
|
|
|
float QtPlayer::Volume() {
|
|
|
|
|
return volume;
|
|
|
|
|
}
|
2014-03-23 01:12:29 -05:00
|
|
|
|
2019-09-21 00:14:32 -04:00
|
|
|
// Set the Volume multiplier (1.0 = normal volume, <1.0 = quieter, >1.0 louder)
|
|
|
|
|
void QtPlayer::Volume(float new_volume) {
|
|
|
|
|
volume = new_volume;
|
|
|
|
|
}
|
Audio: New device name lookup
- A new AudioDevices class replaces the AudioDeviceInfo struct.
It has a single method, getNames(), which:
* creates an AudioDeviceManager (NOT using the singleton)
* scans for available devices
* returns the results as a std::vector containing
std::pair<std::string, std::string> objects
(The AudioDevices device manager is never initialize()d, so
no devices are opened; it should be safe to use even DURING
playback, without disruption.)
By using STL containers (rather than a custom struct) to return
the results, Python is able to consume the output as a native
list of tuples.
AudioDeviceInfo is still present for compatibility, but deprecated.
- Eliminated some unnecessary conversions (like):
* calls to std::string::c_str, when passing to juce::String.
juce::String accepts std::string directly.
* calls to juce::String::toRawUTF8, when creating std::string.
There's a juce::String::ToStdString, which is better.
2021-08-24 13:03:46 -04:00
|
|
|
}
|