Files
libopenshot/src/QtPlayer.cpp
Jonathan Thomas 186a4ca5c1 Refactoring Audio Device detection (don't crash on Windows, find actual sample rate and device details) (#883)
* Close down ZMQ context to stop the zmq threads (related to sentry bug: OPENSHOT-3X)

* Add Support for Windows 7/8.1 (#881)

Adding protection around getting current sample rate for win 7, if audio device not found. Also added mutex for Singleton method. Also, making whitespace consistent on AudioPlaybackThread.cpp

* Big refactor of audio device opening - with multiple sample rates attempted, for better recovery from a missing or unsupported sample rate. Debug logs added for testing.

* Additional failure logging for windows audio device init

* Refactor of Audio Device Initialization (#882)

* Huge refactor of audio device initialization:
- Attempt requested audio device first, and then iterate through all known audio types and devices, and common sample rates. The idea is to ignore an invalid default or invalid requested device, and keep looking until we find a valid one
- New public method to return active, open audio device
- Added methods for AudioDeviceInfo struct, to make it callable from Python
- Some code clean-up and whitespace fixes
- New unit tests for AudioDeviceManagerSingleton

* Ignore audio device unit tests on systems with "No Driver" returned in the audio error message

* Ignore audio device unit tests if any error is found during initialization (i.e. build servers don't have audio cards)

* Trying to update GitHub libomp errors during build checks

* Remove zmq context shutdown call, due to the method missing on newer versions of zmq.hpp

* Downgrading GitHub Ubuntu latest image to Ubuntu 20.04, for compatibility with Catchv2

* Initialize all audio device manager variables correctly, and ignore unit test on low or missing sample rate systems (i.e. GitHub build servers)
2022-12-19 13:15:43 -06:00

250 lines
6.4 KiB
C++

/**
* @file
* @brief Source file for QtPlayer class
* @author Duzy Chan <code@duzy.info>
* @author Jonathan Thomas <jonathan@openshot.org>
*
* @ref License
*/
// Copyright (c) 2008-2019 OpenShot Studios, LLC
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "QtPlayer.h"
#include "AudioDevices.h"
#include "Clip.h"
#include "FFmpegReader.h"
#include "Timeline.h"
#include "Qt/PlayerPrivate.h"
#include "Qt/VideoRenderer.h"
namespace openshot
{
using AudioDeviceList = std::vector<std::pair<std::string, std::string>>;
// Delegating constructor
QtPlayer::QtPlayer()
: QtPlayer::QtPlayer(new VideoRenderer())
{ }
// Constructor
QtPlayer::QtPlayer(openshot::RendererBase *rb)
: PlayerBase()
, p(new openshot::PlayerPrivate(rb))
, threads_started(false)
{
reader = NULL;
}
QtPlayer::~QtPlayer()
{
if (mode != PLAYBACK_STOPPED)
Stop();
delete p;
}
void QtPlayer::CloseAudioDevice()
{
// Close audio device (only do this once, when all audio playback is finished)
openshot::AudioDeviceManagerSingleton::Instance()->CloseAudioDevice();
}
// Return any error string during initialization
std::string QtPlayer::GetError() {
if (reader && threads_started) {
return p->audioPlayback->getError();
} else {
return "";
}
}
// Return the default audio sample rate (from the system)
double QtPlayer::GetDefaultSampleRate() {
if (reader && threads_started) {
return p->audioPlayback->getDefaultSampleRate();
} else {
return 0;
}
}
/// Get vector of audio device names & types
AudioDeviceList QtPlayer::GetAudioDeviceNames() {
AudioDevices devs;
return devs.getNames();
}
// Get current audio device or last attempted (if none succeeded)
AudioDeviceInfo QtPlayer::GetCurrentAudioDevice() {
return p->audioPlayback->getCurrentAudioDevice();
}
// 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);
}
void QtPlayer::SetSource(const std::string &source)
{
FFmpegReader *ffreader = new FFmpegReader(source);
ffreader->DisplayInfo();
// 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);
Clip *c = new Clip(source);
Timeline* tm = (Timeline*)reader;
tm->AddClip(c);
tm->Open();
// Set the reader
Reader(reader);
}
void QtPlayer::Play()
{
// Set mode to playing, and speed to normal
mode = PLAYBACK_PLAY;
Speed(1);
if (reader && !threads_started) {
// Start thread only once
p->startPlayback();
threads_started = true;
}
}
void QtPlayer::Loading()
{
mode = PLAYBACK_LOADING;
}
/// Get the current mode
openshot::PlaybackMode QtPlayer::Mode()
{
return mode;
}
void QtPlayer::Pause()
{
mode = PLAYBACK_PAUSED;
Speed(0);
}
int64_t QtPlayer::Position()
{
return p->video_position;
}
void QtPlayer::Seek(int64_t new_frame)
{
// Check for seek
if (reader && threads_started && new_frame > 0) {
// Notify cache thread that seek has occurred
p->videoCache->Seek(new_frame, true);
// Notify audio thread that seek has occurred
p->audioPlayback->Seek(new_frame);
// Update current position
p->Seek(new_frame);
}
}
void QtPlayer::Stop()
{
// Change mode to stopped
mode = PLAYBACK_STOPPED;
// Notify threads of stopping
if (reader && threads_started) {
p->videoCache->Stop();
p->audioPlayback->Stop();
// Kill all threads
p->stopPlayback();
}
p->video_position = 0;
threads_started = false;
}
// 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);
}
// Get the current reader, such as a FFmpegReader
openshot::ReaderBase* QtPlayer::Reader() {
return reader;
}
// 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);
}
// Get the Renderer pointer address (for Python to cast back into a QObject)
int64_t QtPlayer::GetRendererQObject() {
return (int64_t)(VideoRenderer*)p->renderer;
}
// 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;
p->videoCache->setSpeed(new_speed);
if (p->reader && p->reader->info.has_audio) {
p->audioPlayback->setSpeed(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;
}
}