mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 15:45:38 +00:00
Replaced some mutex locks with atomic variables.
Also removed an SDL audio issue workaround from AudioManager.
This commit is contained in:
parent
7f5fe3fcbf
commit
9937476e18
|
@ -194,9 +194,7 @@ void AudioManager::mixAudio(void* /*unused*/, Uint8* stream, int len)
|
||||||
// stream is not played when the video player has been stopped. Otherwise there would
|
// stream is not played when the video player has been stopped. Otherwise there would
|
||||||
// be a short time period when the audio would keep playing after the video was stopped
|
// be a short time period when the audio would keep playing after the video was stopped
|
||||||
// and before the stream was cleared in clearStream().
|
// and before the stream was cleared in clearStream().
|
||||||
std::unique_lock<std::mutex> audioLock{mAudioLock};
|
|
||||||
bool muteStream = sMuteStream;
|
bool muteStream = sMuteStream;
|
||||||
audioLock.unlock();
|
|
||||||
if (muteStream) {
|
if (muteStream) {
|
||||||
SDL_MixAudioFormat(stream, &converted.at(0), sAudioFormat.format, processedLength, 0);
|
SDL_MixAudioFormat(stream, &converted.at(0), sAudioFormat.format, processedLength, 0);
|
||||||
}
|
}
|
||||||
|
@ -290,41 +288,4 @@ void AudioManager::clearStream()
|
||||||
SDL_LockAudioDevice(sAudioDevice);
|
SDL_LockAudioDevice(sAudioDevice);
|
||||||
SDL_AudioStreamClear(sConversionStream);
|
SDL_AudioStreamClear(sConversionStream);
|
||||||
SDL_UnlockAudioDevice(sAudioDevice);
|
SDL_UnlockAudioDevice(sAudioDevice);
|
||||||
|
|
||||||
// TEMPORARY: For evaluating if SDL_AudioStreamClear is stable.
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If sSoundVector is empty it means we are shutting down. In this case don't attempt
|
|
||||||
// to clear the stream as this could lead to a crash.
|
|
||||||
if (sSoundVector.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
SDL_LockAudioDevice(sAudioDevice);
|
|
||||||
|
|
||||||
// This code is required as there's seemingly a bug in SDL_AudioStreamAvailable().
|
|
||||||
// The function sometimes returns 0 even if there is data left in the buffer, possibly
|
|
||||||
// because the remaining data is less than the configured sample size. It happens almost
|
|
||||||
// permanently on NetBSD but also on at least Linux from time to time. Adding some data
|
|
||||||
// to the stream buffer to get above this threshold before calling the function will
|
|
||||||
// return the proper number. So adding 10000 as we do here would give a return value of
|
|
||||||
// for instance 10880 instead of 0, assuming there were 880 bytes of data left in the buffer.
|
|
||||||
// Fortunately the SDL_AudioStreamGet() function acts correctly on any arbitrary sample size
|
|
||||||
// so we can actually clear the entire buffer. If this workaround was not implemented, there
|
|
||||||
// would be a sound glitch when some samples from the previous video would play any time a
|
|
||||||
// new video was started (assuming the issue was triggered by some remaining stream data).
|
|
||||||
std::vector<Uint8> writeBuffer(10000);
|
|
||||||
if (SDL_AudioStreamPut(sConversionStream, reinterpret_cast<const void*>(&writeBuffer.at(0)),
|
|
||||||
10000) == -1) {
|
|
||||||
LOG(LogError) << "Failed to put samples in the conversion stream:";
|
|
||||||
LOG(LogError) << SDL_GetError();
|
|
||||||
SDL_UnlockAudioDevice(sAudioDevice);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length = SDL_AudioStreamAvailable(sConversionStream);
|
|
||||||
|
|
||||||
std::vector<Uint8> readBuffer(length);
|
|
||||||
SDL_AudioStreamGet(sConversionStream, static_cast<void*>(&readBuffer.at(0)), length);
|
|
||||||
|
|
||||||
SDL_UnlockAudioDevice(sAudioDevice);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#define ES_CORE_AUDIO_MANAGER_H
|
#define ES_CORE_AUDIO_MANAGER_H
|
||||||
|
|
||||||
#include <SDL2/SDL_audio.h>
|
#include <SDL2/SDL_audio.h>
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class Sound;
|
class Sound;
|
||||||
|
@ -36,16 +36,8 @@ public:
|
||||||
void processStream(const void* samples, unsigned count);
|
void processStream(const void* samples, unsigned count);
|
||||||
void clearStream();
|
void clearStream();
|
||||||
|
|
||||||
void muteStream()
|
void muteStream() { sMuteStream = true; }
|
||||||
{
|
void unmuteStream() { sMuteStream = false; }
|
||||||
std::unique_lock<std::mutex> audioLock{mAudioLock};
|
|
||||||
sMuteStream = true;
|
|
||||||
}
|
|
||||||
void unmuteStream()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> audioLock{mAudioLock};
|
|
||||||
sMuteStream = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getHasAudioDevice() { return sHasAudioDevice; }
|
bool getHasAudioDevice() { return sHasAudioDevice; }
|
||||||
|
|
||||||
|
@ -58,10 +50,9 @@ private:
|
||||||
static void mixAudio(void* unused, Uint8* stream, int len);
|
static void mixAudio(void* unused, Uint8* stream, int len);
|
||||||
static void mixAudio2(void* unused, Uint8* stream, int len);
|
static void mixAudio2(void* unused, Uint8* stream, int len);
|
||||||
|
|
||||||
inline static std::mutex mAudioLock;
|
|
||||||
inline static SDL_AudioStream* sConversionStream;
|
inline static SDL_AudioStream* sConversionStream;
|
||||||
inline static std::vector<std::shared_ptr<Sound>> sSoundVector;
|
inline static std::vector<std::shared_ptr<Sound>> sSoundVector;
|
||||||
inline static bool sMuteStream = false;
|
inline static std::atomic<bool> sMuteStream = false;
|
||||||
inline static bool sHasAudioDevice = true;
|
inline static bool sHasAudioDevice = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -151,8 +151,6 @@ void Sound::play()
|
||||||
|
|
||||||
SDL_LockAudioDevice(AudioManager::sAudioDevice);
|
SDL_LockAudioDevice(AudioManager::sAudioDevice);
|
||||||
|
|
||||||
std::unique_lock<std::mutex> playerLock(mMutex);
|
|
||||||
|
|
||||||
if (mPlaying)
|
if (mPlaying)
|
||||||
// Replay from start. rewind the sample to the beginning.
|
// Replay from start. rewind the sample to the beginning.
|
||||||
mSamplePos = 0;
|
mSamplePos = 0;
|
||||||
|
@ -160,8 +158,6 @@ void Sound::play()
|
||||||
// Flag our sample as playing.
|
// Flag our sample as playing.
|
||||||
mPlaying = true;
|
mPlaying = true;
|
||||||
|
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
SDL_UnlockAudioDevice(AudioManager::sAudioDevice);
|
SDL_UnlockAudioDevice(AudioManager::sAudioDevice);
|
||||||
// Tell the AudioManager to start playing samples.
|
// Tell the AudioManager to start playing samples.
|
||||||
AudioManager::getInstance().play();
|
AudioManager::getInstance().play();
|
||||||
|
@ -171,7 +167,6 @@ void Sound::stop()
|
||||||
{
|
{
|
||||||
// Flag our sample as not playing and rewind its position.
|
// Flag our sample as not playing and rewind its position.
|
||||||
SDL_LockAudioDevice(AudioManager::sAudioDevice);
|
SDL_LockAudioDevice(AudioManager::sAudioDevice);
|
||||||
std::unique_lock<std::mutex> playerLock(mMutex);
|
|
||||||
mPlaying = false;
|
mPlaying = false;
|
||||||
mSamplePos = 0;
|
mSamplePos = 0;
|
||||||
SDL_UnlockAudioDevice(AudioManager::sAudioDevice);
|
SDL_UnlockAudioDevice(AudioManager::sAudioDevice);
|
||||||
|
@ -182,7 +177,6 @@ void Sound::setPosition(Uint32 newPosition)
|
||||||
mSamplePos = newPosition;
|
mSamplePos = newPosition;
|
||||||
if (mSamplePos >= mSampleLength) {
|
if (mSamplePos >= mSampleLength) {
|
||||||
// Got to or beyond the end of the sample. stop playing.
|
// Got to or beyond the end of the sample. stop playing.
|
||||||
std::unique_lock<std::mutex> playerLock(mMutex);
|
|
||||||
mPlaying = false;
|
mPlaying = false;
|
||||||
mSamplePos = 0;
|
mSamplePos = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
#define ES_CORE_SOUND_H
|
#define ES_CORE_SOUND_H
|
||||||
|
|
||||||
#include <SDL2/SDL_audio.h>
|
#include <SDL2/SDL_audio.h>
|
||||||
|
#include <atomic>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -31,11 +31,7 @@ public:
|
||||||
void loadFile(const std::string& path);
|
void loadFile(const std::string& path);
|
||||||
|
|
||||||
void play();
|
void play();
|
||||||
bool isPlaying() const
|
bool isPlaying() const { return mPlaying; }
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> playerLock(mMutex);
|
|
||||||
return mPlaying;
|
|
||||||
}
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
const Uint8* getData() const { return mSampleData; }
|
const Uint8* getData() const { return mSampleData; }
|
||||||
|
@ -51,14 +47,13 @@ public:
|
||||||
private:
|
private:
|
||||||
Sound(const std::string& path = "");
|
Sound(const std::string& path = "");
|
||||||
|
|
||||||
inline static std::mutex mMutex;
|
|
||||||
static std::map<std::string, std::shared_ptr<Sound>> sMap;
|
static std::map<std::string, std::shared_ptr<Sound>> sMap;
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
SDL_AudioSpec mSampleFormat;
|
SDL_AudioSpec mSampleFormat;
|
||||||
Uint8* mSampleData;
|
Uint8* mSampleData;
|
||||||
Uint32 mSamplePos;
|
Uint32 mSamplePos;
|
||||||
Uint32 mSampleLength;
|
Uint32 mSampleLength;
|
||||||
bool mPlaying;
|
std::atomic<bool> mPlaying;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NavigationSoundsID {
|
enum NavigationSoundsID {
|
||||||
|
|
|
@ -799,26 +799,14 @@ void Window::closeLaunchScreen()
|
||||||
mRenderLaunchScreen = false;
|
mRenderLaunchScreen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::increaseVideoPlayerCount()
|
void Window::increaseVideoPlayerCount() { mVideoPlayerCount++; }
|
||||||
{
|
|
||||||
mVideoCountMutex.lock();
|
|
||||||
mVideoPlayerCount++;
|
|
||||||
mVideoCountMutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::decreaseVideoPlayerCount()
|
void Window::decreaseVideoPlayerCount() { mVideoPlayerCount--; }
|
||||||
{
|
|
||||||
mVideoCountMutex.lock();
|
|
||||||
mVideoPlayerCount--;
|
|
||||||
mVideoCountMutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Window::getVideoPlayerCount()
|
int Window::getVideoPlayerCount()
|
||||||
{
|
{
|
||||||
int videoPlayerCount;
|
int videoPlayerCount;
|
||||||
mVideoCountMutex.lock();
|
|
||||||
videoPlayerCount = mVideoPlayerCount;
|
videoPlayerCount = mVideoPlayerCount;
|
||||||
mVideoCountMutex.unlock();
|
|
||||||
return videoPlayerCount;
|
return videoPlayerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "resources/TextureResource.h"
|
#include "resources/TextureResource.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
class FileData;
|
class FileData;
|
||||||
|
@ -192,8 +192,7 @@ private:
|
||||||
bool mCachedBackground;
|
bool mCachedBackground;
|
||||||
bool mInvalidatedCachedBackground;
|
bool mInvalidatedCachedBackground;
|
||||||
|
|
||||||
int mVideoPlayerCount;
|
std::atomic<int> mVideoPlayerCount;
|
||||||
std::mutex mVideoCountMutex;
|
|
||||||
|
|
||||||
float mTopScale;
|
float mTopScale;
|
||||||
bool mRenderedHelpPrompts;
|
bool mRenderedHelpPrompts;
|
||||||
|
|
|
@ -90,12 +90,9 @@ void VideoComponent::setImage(std::string path)
|
||||||
|
|
||||||
void VideoComponent::onShow()
|
void VideoComponent::onShow()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mBlockPlayer = false;
|
mBlockPlayer = false;
|
||||||
mPause = false;
|
mPause = false;
|
||||||
mShowing = true;
|
mShowing = true;
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
manageState();
|
manageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,30 +110,22 @@ void VideoComponent::onStopVideo()
|
||||||
|
|
||||||
void VideoComponent::onPauseVideo()
|
void VideoComponent::onPauseVideo()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mBlockPlayer = true;
|
mBlockPlayer = true;
|
||||||
mPause = true;
|
mPause = true;
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
manageState();
|
manageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoComponent::onUnpauseVideo()
|
void VideoComponent::onUnpauseVideo()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mBlockPlayer = false;
|
mBlockPlayer = false;
|
||||||
mPause = false;
|
mPause = false;
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
manageState();
|
manageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoComponent::onScreensaverActivate()
|
void VideoComponent::onScreensaverActivate()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mBlockPlayer = true;
|
mBlockPlayer = true;
|
||||||
mPause = true;
|
mPause = true;
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
if (Settings::getInstance()->getString("ScreensaverType") == "dim")
|
if (Settings::getInstance()->getString("ScreensaverType") == "dim")
|
||||||
stopVideo();
|
stopVideo();
|
||||||
|
@ -170,20 +159,16 @@ void VideoComponent::onGameLaunchedDeactivate()
|
||||||
void VideoComponent::topWindow(bool isTop)
|
void VideoComponent::topWindow(bool isTop)
|
||||||
{
|
{
|
||||||
if (isTop) {
|
if (isTop) {
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mBlockPlayer = false;
|
mBlockPlayer = false;
|
||||||
mPause = false;
|
mPause = false;
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
// Stop video when closing the menu to force a reload of the
|
// Stop video when closing the menu to force a reload of the
|
||||||
// static image (if the theme is configured as such).
|
// static image (if the theme is configured as such).
|
||||||
stopVideo();
|
stopVideo();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mBlockPlayer = true;
|
mBlockPlayer = true;
|
||||||
mPause = true;
|
mPause = true;
|
||||||
playerLock.unlock();
|
|
||||||
}
|
}
|
||||||
manageState();
|
manageState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
#include "components/ImageComponent.h"
|
#include "components/ImageComponent.h"
|
||||||
|
|
||||||
#include <mutex>
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class MediaViewer;
|
class MediaViewer;
|
||||||
|
@ -110,7 +110,6 @@ private:
|
||||||
protected:
|
protected:
|
||||||
Window* mWindow;
|
Window* mWindow;
|
||||||
ImageComponent mStaticImage;
|
ImageComponent mStaticImage;
|
||||||
std::mutex mPlayerMutex;
|
|
||||||
|
|
||||||
unsigned mVideoWidth;
|
unsigned mVideoWidth;
|
||||||
unsigned mVideoHeight;
|
unsigned mVideoHeight;
|
||||||
|
@ -124,9 +123,9 @@ protected:
|
||||||
std::string mPlayingVideoPath;
|
std::string mPlayingVideoPath;
|
||||||
unsigned mStartTime;
|
unsigned mStartTime;
|
||||||
bool mStartDelayed;
|
bool mStartDelayed;
|
||||||
bool mIsPlaying;
|
std::atomic<bool> mIsPlaying;
|
||||||
bool mIsActuallyPlaying;
|
std::atomic<bool> mIsActuallyPlaying;
|
||||||
bool mPause;
|
std::atomic<bool> mPause;
|
||||||
bool mShowing;
|
bool mShowing;
|
||||||
bool mDisable;
|
bool mDisable;
|
||||||
bool mMediaViewerMode;
|
bool mMediaViewerMode;
|
||||||
|
|
|
@ -130,10 +130,8 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
||||||
|
|
||||||
if (mIsPlaying && mFormatContext) {
|
if (mIsPlaying && mFormatContext) {
|
||||||
unsigned int color;
|
unsigned int color;
|
||||||
std::unique_lock<std::mutex> pictureLock(mPictureMutex);
|
|
||||||
bool decodedFrame = mDecodedFrame;
|
if (mDecodedFrame && mFadeIn < 1) {
|
||||||
pictureLock.unlock();
|
|
||||||
if (decodedFrame && mFadeIn < 1) {
|
|
||||||
const unsigned int fadeIn = static_cast<int>(mFadeIn * 255.0f);
|
const unsigned int fadeIn = static_cast<int>(mFadeIn * 255.0f);
|
||||||
color =
|
color =
|
||||||
Renderer::convertRGBAToABGR((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255);
|
Renderer::convertRGBAToABGR((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255);
|
||||||
|
@ -162,13 +160,11 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
vertices[i].pos = glm::round(vertices[i].pos);
|
vertices[i].pos = glm::round(vertices[i].pos);
|
||||||
|
|
||||||
pictureLock.lock();
|
|
||||||
|
|
||||||
// This is needed to avoid a slight gap before the video starts playing.
|
// This is needed to avoid a slight gap before the video starts playing.
|
||||||
if (!mDecodedFrame) {
|
if (!mDecodedFrame)
|
||||||
pictureLock.unlock();
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
std::unique_lock<std::mutex> pictureLock(mPictureMutex);
|
||||||
|
|
||||||
if (!mOutputPicture.hasBeenRendered) {
|
if (!mOutputPicture.hasBeenRendered) {
|
||||||
// Move the contents of mOutputPicture to a temporary vector in order to call
|
// Move the contents of mOutputPicture to a temporary vector in order to call
|
||||||
|
@ -238,7 +234,8 @@ void VideoFFmpegComponent::updatePlayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsActuallyPlaying && mStartTimeAccumulation) {
|
if (mIsActuallyPlaying && mStartTimeAccumulation) {
|
||||||
mAccumulatedTime +=
|
mAccumulatedTime =
|
||||||
|
mAccumulatedTime +
|
||||||
static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(
|
static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||||
std::chrono::high_resolution_clock::now() - mTimeReference)
|
std::chrono::high_resolution_clock::now() - mTimeReference)
|
||||||
.count()) /
|
.count()) /
|
||||||
|
@ -268,18 +265,16 @@ void VideoFFmpegComponent::frameProcessing()
|
||||||
if (mAudioCodecContext)
|
if (mAudioCodecContext)
|
||||||
audioFilter = setupAudioFilters();
|
audioFilter = setupAudioFilters();
|
||||||
|
|
||||||
bool isPlaying = true;
|
while (mIsPlaying && !mPause && videoFilter && (!mAudioCodecContext || audioFilter)) {
|
||||||
bool pause = false;
|
|
||||||
|
|
||||||
while (isPlaying && !pause && videoFilter && (!mAudioCodecContext || audioFilter)) {
|
|
||||||
readFrames();
|
readFrames();
|
||||||
getProcessedFrames();
|
if (!mIsPlaying)
|
||||||
outputFrames();
|
break;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
getProcessedFrames();
|
||||||
isPlaying = mIsPlaying;
|
if (!mIsPlaying)
|
||||||
pause = mPause;
|
break;
|
||||||
playerLock.unlock();
|
|
||||||
|
outputFrames();
|
||||||
|
|
||||||
// This 1 ms wait makes sure that the thread does not consume all available CPU cycles.
|
// This 1 ms wait makes sure that the thread does not consume all available CPU cycles.
|
||||||
SDL_Delay(1);
|
SDL_Delay(1);
|
||||||
|
@ -672,11 +667,9 @@ void VideoFFmpegComponent::readFrames()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readFrameReturn < 0) {
|
if (readFrameReturn < 0)
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mEndOfVideo = true;
|
mEndOfVideo = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void VideoFFmpegComponent::getProcessedFrames()
|
void VideoFFmpegComponent::getProcessedFrames()
|
||||||
{
|
{
|
||||||
|
@ -761,11 +754,7 @@ void VideoFFmpegComponent::outputFrames()
|
||||||
// Process the audio frames that have a PTS value below mAccumulatedTime (plus a small
|
// Process the audio frames that have a PTS value below mAccumulatedTime (plus a small
|
||||||
// buffer to avoid underflows).
|
// buffer to avoid underflows).
|
||||||
while (!mAudioFrameQueue.empty()) {
|
while (!mAudioFrameQueue.empty()) {
|
||||||
std::unique_lock<std::mutex> audioLock(mAudioMutex);
|
if (mAudioFrameQueue.front().pts < mAccumulatedTime + AUDIO_BUFFER) {
|
||||||
auto accumulatedTime = mAccumulatedTime;
|
|
||||||
audioLock.unlock();
|
|
||||||
|
|
||||||
if (mAudioFrameQueue.front().pts < accumulatedTime + AUDIO_BUFFER) {
|
|
||||||
// Enable only when needed, as this generates a lot of debug output.
|
// Enable only when needed, as this generates a lot of debug output.
|
||||||
if (DEBUG_VIDEO) {
|
if (DEBUG_VIDEO) {
|
||||||
LOG(LogDebug) << "Processing audio frame with PTS: "
|
LOG(LogDebug) << "Processing audio frame with PTS: "
|
||||||
|
@ -787,7 +776,7 @@ void VideoFFmpegComponent::outputFrames()
|
||||||
|
|
||||||
if (outputSound) {
|
if (outputSound) {
|
||||||
// The audio is output to AudioManager from updatePlayer() in the main thread.
|
// The audio is output to AudioManager from updatePlayer() in the main thread.
|
||||||
audioLock.lock();
|
std::unique_lock<std::mutex> audioLock(mAudioMutex);
|
||||||
|
|
||||||
mOutputAudio.insert(mOutputAudio.end(),
|
mOutputAudio.insert(mOutputAudio.end(),
|
||||||
mAudioFrameQueue.front().resampledData.begin(),
|
mAudioFrameQueue.front().resampledData.begin(),
|
||||||
|
@ -803,19 +792,11 @@ void VideoFFmpegComponent::outputFrames()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
bool isActuallyPlaying = mIsActuallyPlaying;
|
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
// Process all available video frames that have a PTS value below mAccumulatedTime.
|
// Process all available video frames that have a PTS value below mAccumulatedTime.
|
||||||
// But if more than one frame is processed here, it means that the computer can't
|
// But if more than one frame is processed here, it means that the computer can't
|
||||||
// keep up for some reason.
|
// keep up for some reason.
|
||||||
while (isActuallyPlaying && !mVideoFrameQueue.empty()) {
|
while (mIsActuallyPlaying && !mVideoFrameQueue.empty()) {
|
||||||
std::unique_lock<std::mutex> audioLock(mAudioMutex);
|
if (mVideoFrameQueue.front().pts < mAccumulatedTime) {
|
||||||
double accumulatedTime = mAccumulatedTime;
|
|
||||||
audioLock.unlock();
|
|
||||||
|
|
||||||
if (mVideoFrameQueue.front().pts < accumulatedTime) {
|
|
||||||
// Enable only when needed, as this generates a lot of debug output.
|
// Enable only when needed, as this generates a lot of debug output.
|
||||||
if (DEBUG_VIDEO) {
|
if (DEBUG_VIDEO) {
|
||||||
LOG(LogDebug) << "Processing video frame with PTS: "
|
LOG(LogDebug) << "Processing video frame with PTS: "
|
||||||
|
@ -843,7 +824,7 @@ void VideoFFmpegComponent::outputFrames()
|
||||||
// can't keep up. This approach primarily decreases stuttering for videos with frame
|
// can't keep up. This approach primarily decreases stuttering for videos with frame
|
||||||
// rates close to, or at, the rendering frame rate, for example 59.94 and 60 FPS.
|
// rates close to, or at, the rendering frame rate, for example 59.94 and 60 FPS.
|
||||||
if (mDecodedFrame && !mOutputPicture.hasBeenRendered) {
|
if (mDecodedFrame && !mOutputPicture.hasBeenRendered) {
|
||||||
double timeDifference = accumulatedTime - mVideoFrameQueue.front().pts -
|
double timeDifference = mAccumulatedTime - mVideoFrameQueue.front().pts -
|
||||||
mVideoFrameQueue.front().frameDuration * 2.0l;
|
mVideoFrameQueue.front().frameDuration * 2.0l;
|
||||||
if (timeDifference < mVideoFrameQueue.front().frameDuration) {
|
if (timeDifference < mVideoFrameQueue.front().frameDuration) {
|
||||||
pictureLock.unlock();
|
pictureLock.unlock();
|
||||||
|
@ -1408,13 +1389,11 @@ void VideoFFmpegComponent::startVideo()
|
||||||
|
|
||||||
void VideoFFmpegComponent::stopVideo()
|
void VideoFFmpegComponent::stopVideo()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
|
||||||
mIsPlaying = false;
|
mIsPlaying = false;
|
||||||
mIsActuallyPlaying = false;
|
mIsActuallyPlaying = false;
|
||||||
mStartDelayed = false;
|
mStartDelayed = false;
|
||||||
mPause = false;
|
mPause = false;
|
||||||
mEndOfVideo = false;
|
mEndOfVideo = false;
|
||||||
playerLock.unlock();
|
|
||||||
mTexture.reset();
|
mTexture.reset();
|
||||||
|
|
||||||
if (mFrameProcessingThread) {
|
if (mFrameProcessingThread) {
|
||||||
|
@ -1459,11 +1438,7 @@ void VideoFFmpegComponent::pauseVideo()
|
||||||
|
|
||||||
void VideoFFmpegComponent::handleLooping()
|
void VideoFFmpegComponent::handleLooping()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> playerLock(mPlayerMutex);
|
if (mIsPlaying && mEndOfVideo) {
|
||||||
bool endOfVideo = mEndOfVideo;
|
|
||||||
playerLock.unlock();
|
|
||||||
|
|
||||||
if (mIsPlaying && endOfVideo) {
|
|
||||||
// If the screensaver video swap time is set to 0, it means we should
|
// If the screensaver video swap time is set to 0, it means we should
|
||||||
// skip to the next game when the video has finished playing.
|
// skip to the next game when the video has finished playing.
|
||||||
if (mScreensaverMode &&
|
if (mScreensaverMode &&
|
||||||
|
|
|
@ -23,6 +23,7 @@ extern "C" {
|
||||||
#include <libavutil/imgutils.h>
|
#include <libavutil/imgutils.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
@ -161,10 +162,10 @@ private:
|
||||||
int mVideoFrameReadCount;
|
int mVideoFrameReadCount;
|
||||||
int mVideoFrameDroppedCount;
|
int mVideoFrameDroppedCount;
|
||||||
|
|
||||||
double mAccumulatedTime;
|
std::atomic<double> mAccumulatedTime;
|
||||||
bool mStartTimeAccumulation;
|
std::atomic<bool> mStartTimeAccumulation;
|
||||||
bool mDecodedFrame;
|
std::atomic<bool> mDecodedFrame;
|
||||||
bool mEndOfVideo;
|
std::atomic<bool> mEndOfVideo;
|
||||||
bool mSWDecoder;
|
bool mSWDecoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -179,9 +179,7 @@ bool TextureData::load()
|
||||||
const ResourceData& data = rm->getFileData(mPath);
|
const ResourceData& data = rm->getFileData(mPath);
|
||||||
// Is it an SVG?
|
// Is it an SVG?
|
||||||
if (Utils::String::toLower(mPath.substr(mPath.size() - 4, std::string::npos)) == ".svg") {
|
if (Utils::String::toLower(mPath.substr(mPath.size() - 4, std::string::npos)) == ".svg") {
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
|
||||||
mScalable = true;
|
mScalable = true;
|
||||||
lock.unlock();
|
|
||||||
std::string dataString;
|
std::string dataString;
|
||||||
dataString.assign(std::string(reinterpret_cast<char*>(data.ptr.get()), data.length));
|
dataString.assign(std::string(reinterpret_cast<char*>(data.ptr.get()), data.length));
|
||||||
retval = initSVGFromMemory(dataString);
|
retval = initSVGFromMemory(dataString);
|
||||||
|
@ -285,11 +283,7 @@ float TextureData::sourceHeight()
|
||||||
|
|
||||||
void TextureData::setSourceSize(float width, float height)
|
void TextureData::setSourceSize(float width, float height)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
if (mScalable) {
|
||||||
bool scalable = mScalable;
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
if (scalable) {
|
|
||||||
if ((mSourceWidth != width) || (mSourceHeight != height)) {
|
if ((mSourceWidth != width) || (mSourceHeight != height)) {
|
||||||
mSourceWidth = width;
|
mSourceWidth = width;
|
||||||
mSourceHeight = height;
|
mSourceHeight = height;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "utils/MathUtil.h"
|
#include "utils/MathUtil.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -79,7 +80,7 @@ private:
|
||||||
int mHeight;
|
int mHeight;
|
||||||
float mSourceWidth;
|
float mSourceWidth;
|
||||||
float mSourceHeight;
|
float mSourceHeight;
|
||||||
bool mScalable;
|
std::atomic<bool> mScalable;
|
||||||
bool mLinearMagnify;
|
bool mLinearMagnify;
|
||||||
bool mReloadable;
|
bool mReloadable;
|
||||||
bool mForceRasterization;
|
bool mForceRasterization;
|
||||||
|
|
|
@ -161,10 +161,11 @@ TextureLoader::~TextureLoader()
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
mTextureDataQ.clear();
|
mTextureDataQ.clear();
|
||||||
mTextureDataLookup.clear();
|
mTextureDataLookup.clear();
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
// Exit the thread.
|
// Exit the thread.
|
||||||
mExit = true;
|
mExit = true;
|
||||||
lock.unlock();
|
|
||||||
mEvent.notify_one();
|
mEvent.notify_one();
|
||||||
mThread->join();
|
mThread->join();
|
||||||
mThread.reset();
|
mThread.reset();
|
||||||
|
@ -172,9 +173,7 @@ TextureLoader::~TextureLoader()
|
||||||
|
|
||||||
void TextureLoader::threadProc()
|
void TextureLoader::threadProc()
|
||||||
{
|
{
|
||||||
bool exit = false;
|
while (!mExit) {
|
||||||
|
|
||||||
while (!exit) {
|
|
||||||
std::shared_ptr<TextureData> textureData;
|
std::shared_ptr<TextureData> textureData;
|
||||||
{
|
{
|
||||||
// Wait for an event to say there is something in the queue.
|
// Wait for an event to say there is something in the queue.
|
||||||
|
@ -199,7 +198,6 @@ void TextureLoader::threadProc()
|
||||||
mTextureDataLookup.erase(mTextureDataLookup.find(textureData.get()));
|
mTextureDataLookup.erase(mTextureDataLookup.find(textureData.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit = mExit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef ES_CORE_RESOURCES_TEXTURE_DATA_MANAGER_H
|
#ifndef ES_CORE_RESOURCES_TEXTURE_DATA_MANAGER_H
|
||||||
#define ES_CORE_RESOURCES_TEXTURE_DATA_MANAGER_H
|
#define ES_CORE_RESOURCES_TEXTURE_DATA_MANAGER_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -41,7 +42,7 @@ private:
|
||||||
std::unique_ptr<std::thread> mThread;
|
std::unique_ptr<std::thread> mThread;
|
||||||
std::mutex mMutex;
|
std::mutex mMutex;
|
||||||
std::condition_variable mEvent;
|
std::condition_variable mEvent;
|
||||||
bool mExit;
|
std::atomic<bool> mExit;
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue