mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-23 12:08:45 +02:00
Fix possible memory corruption in video player
Fixes two bugs, one was definitely happening, and 2nd one that is causing undefined behavior and may work only in some std implementations - VideoPlayer would attempt to access subtitles widget after VideoPlayer itself was destroyed in onPlaybackFinished call - std::function was destroyed from a function that is being called by it. Replaced with 1-method interface to avoid usage of std::function in this scenario
This commit is contained in:
parent
3115894307
commit
9fbeacb688
@ -347,6 +347,7 @@ set(vcmiclientcommon_HEADERS
|
|||||||
widgets/CArtifactsOfHeroAltar.h
|
widgets/CArtifactsOfHeroAltar.h
|
||||||
widgets/CArtifactsOfHeroMarket.h
|
widgets/CArtifactsOfHeroMarket.h
|
||||||
widgets/CArtifactsOfHeroBackpack.h
|
widgets/CArtifactsOfHeroBackpack.h
|
||||||
|
widgets/IVideoHolder.h
|
||||||
widgets/RadialMenu.h
|
widgets/RadialMenu.h
|
||||||
widgets/VideoWidget.h
|
widgets/VideoWidget.h
|
||||||
widgets/markets/CAltarArtifacts.h
|
widgets/markets/CAltarArtifacts.h
|
||||||
|
@ -205,7 +205,7 @@ CHighScoreInputScreen::CHighScoreInputScreen(bool won, HighScoreCalculation calc
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
videoPlayer = std::make_shared<VideoWidgetOnce>(Point(0, 0), VideoPath::builtin("LOSEGAME.SMK"), true, [this](){close();});
|
videoPlayer = std::make_shared<VideoWidgetOnce>(Point(0, 0), VideoPath::builtin("LOSEGAME.SMK"), true, this);
|
||||||
CCS->musich->playMusic(AudioPath::builtin("music/UltimateLose"), false, true);
|
CCS->musich->playMusic(AudioPath::builtin("music/UltimateLose"), false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,6 +216,11 @@ CHighScoreInputScreen::CHighScoreInputScreen(bool won, HighScoreCalculation calc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CHighScoreInputScreen::onVideoPlaybackFinished()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
int CHighScoreInputScreen::addEntry(std::string text) {
|
int CHighScoreInputScreen::addEntry(std::string text) {
|
||||||
std::vector<JsonNode> baseNode = persistentStorage["highscore"][calc.isCampaign ? "campaign" : "scenario"].Vector();
|
std::vector<JsonNode> baseNode = persistentStorage["highscore"][calc.isCampaign ? "campaign" : "scenario"].Vector();
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../widgets/IVideoHolder.h"
|
||||||
#include "../windows/CWindowObject.h"
|
#include "../windows/CWindowObject.h"
|
||||||
#include "../../lib/gameState/HighScore.h"
|
#include "../../lib/gameState/HighScore.h"
|
||||||
#include "../../lib/gameState/GameStatistics.h"
|
#include "../../lib/gameState/GameStatistics.h"
|
||||||
@ -69,7 +71,7 @@ public:
|
|||||||
CHighScoreInput(std::string playerName, std::function<void(std::string text)> readyCB);
|
CHighScoreInput(std::string playerName, std::function<void(std::string text)> readyCB);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CHighScoreInputScreen : public CWindowObject
|
class CHighScoreInputScreen : public CWindowObject, public IVideoHolder
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<CLabel>> texts;
|
std::vector<std::shared_ptr<CLabel>> texts;
|
||||||
std::shared_ptr<CHighScoreInput> input;
|
std::shared_ptr<CHighScoreInput> input;
|
||||||
@ -82,6 +84,8 @@ class CHighScoreInputScreen : public CWindowObject
|
|||||||
bool won;
|
bool won;
|
||||||
HighScoreCalculation calc;
|
HighScoreCalculation calc;
|
||||||
StatisticDataSet stat;
|
StatisticDataSet stat;
|
||||||
|
|
||||||
|
void onVideoPlaybackFinished() override;
|
||||||
public:
|
public:
|
||||||
CHighScoreInputScreen(bool won, HighScoreCalculation calc, const StatisticDataSet & statistic);
|
CHighScoreInputScreen(bool won, HighScoreCalculation calc, const StatisticDataSet & statistic);
|
||||||
|
|
||||||
|
17
client/widgets/IVideoHolder.h
Normal file
17
client/widgets/IVideoHolder.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* IVideoHolder.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class IVideoHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IVideoHolder() = default;
|
||||||
|
virtual void onVideoPlaybackFinished() = 0;
|
||||||
|
};
|
@ -10,6 +10,7 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "VideoWidget.h"
|
#include "VideoWidget.h"
|
||||||
#include "TextControls.h"
|
#include "TextControls.h"
|
||||||
|
#include "IVideoHolder.h"
|
||||||
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
@ -172,15 +173,17 @@ void VideoWidgetBase::tick(uint32_t msPassed)
|
|||||||
{
|
{
|
||||||
videoInstance->tick(msPassed);
|
videoInstance->tick(msPassed);
|
||||||
|
|
||||||
|
if(subTitle)
|
||||||
|
subTitle->setText(getSubTitleLine(videoInstance->timeStamp()));
|
||||||
|
|
||||||
if(videoInstance->videoEnded())
|
if(videoInstance->videoEnded())
|
||||||
{
|
{
|
||||||
videoInstance.reset();
|
videoInstance.reset();
|
||||||
stopAudio();
|
stopAudio();
|
||||||
onPlaybackFinished();
|
onPlaybackFinished();
|
||||||
|
// WARNING: onPlaybackFinished call may destoy `this`. Make sure that this is the very last operation in this method!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(subTitle && videoInstance)
|
|
||||||
subTitle->setText(getSubTitleLine(videoInstance->timeStamp()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoWidget::VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped, bool playAudio)
|
VideoWidget::VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped, bool playAudio)
|
||||||
@ -200,19 +203,19 @@ void VideoWidget::onPlaybackFinished()
|
|||||||
playVideo(loopedVideo);
|
playVideo(loopedVideo);
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, const std::function<void()> & callback)
|
VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, IVideoHolder * owner)
|
||||||
: VideoWidgetBase(position, video, playAudio)
|
: VideoWidgetBase(position, video, playAudio)
|
||||||
, callback(callback)
|
, owner(owner)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor, const std::function<void()> & callback)
|
VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor, IVideoHolder * owner)
|
||||||
: VideoWidgetBase(position, video, playAudio, scaleFactor)
|
: VideoWidgetBase(position, video, playAudio, scaleFactor)
|
||||||
, callback(callback)
|
, owner(owner)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoWidgetOnce::onPlaybackFinished()
|
void VideoWidgetOnce::onPlaybackFinished()
|
||||||
{
|
{
|
||||||
callback();
|
owner->onVideoPlaybackFinished();
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "../lib/filesystem/ResourcePath.h"
|
#include "../lib/filesystem/ResourcePath.h"
|
||||||
#include "../lib/json/JsonNode.h"
|
#include "../lib/json/JsonNode.h"
|
||||||
|
|
||||||
|
class IVideoHolder;
|
||||||
class IVideoInstance;
|
class IVideoInstance;
|
||||||
class CMultiLineLabel;
|
class CMultiLineLabel;
|
||||||
|
|
||||||
@ -64,10 +65,10 @@ public:
|
|||||||
|
|
||||||
class VideoWidgetOnce final: public VideoWidgetBase
|
class VideoWidgetOnce final: public VideoWidgetBase
|
||||||
{
|
{
|
||||||
std::function<void()> callback;
|
IVideoHolder * owner;
|
||||||
|
|
||||||
void onPlaybackFinished() final;
|
void onPlaybackFinished() final;
|
||||||
public:
|
public:
|
||||||
VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, const std::function<void()> & callback);
|
VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, IVideoHolder * owner);
|
||||||
VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor, const std::function<void()> & callback);
|
VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor, IVideoHolder * owner);
|
||||||
};
|
};
|
||||||
|
@ -498,20 +498,20 @@ void CSpellWindow::turnPageLeft()
|
|||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
if(settings["video"]["spellbookAnimation"].Bool() && !isBigSpellbook)
|
if(settings["video"]["spellbookAnimation"].Bool() && !isBigSpellbook)
|
||||||
video = std::make_shared<VideoWidgetOnce>(Point(13, 14), VideoPath::builtin("PGTRNLFT.SMK"), false, [this](){
|
video = std::make_shared<VideoWidgetOnce>(Point(13, 14), VideoPath::builtin("PGTRNLFT.SMK"), false, this);
|
||||||
video.reset();
|
|
||||||
redraw();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSpellWindow::turnPageRight()
|
void CSpellWindow::turnPageRight()
|
||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
if(settings["video"]["spellbookAnimation"].Bool() && !isBigSpellbook)
|
if(settings["video"]["spellbookAnimation"].Bool() && !isBigSpellbook)
|
||||||
video = std::make_shared<VideoWidgetOnce>(Point(13, 14), VideoPath::builtin("PGTRNRGH.SMK"), false, [this](){
|
video = std::make_shared<VideoWidgetOnce>(Point(13, 14), VideoPath::builtin("PGTRNRGH.SMK"), false, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSpellWindow::onVideoPlaybackFinished()
|
||||||
|
{
|
||||||
video.reset();
|
video.reset();
|
||||||
redraw();
|
redraw();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSpellWindow::keyPressed(EShortcut key)
|
void CSpellWindow::keyPressed(EShortcut key)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CWindowObject.h"
|
#include "CWindowObject.h"
|
||||||
|
#include "../widgets/IVideoHolder.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ class CToggleButton;
|
|||||||
class VideoWidgetOnce;
|
class VideoWidgetOnce;
|
||||||
|
|
||||||
/// The spell window
|
/// The spell window
|
||||||
class CSpellWindow : public CWindowObject
|
class CSpellWindow : public CWindowObject, public IVideoHolder
|
||||||
{
|
{
|
||||||
class SpellArea : public CIntObject
|
class SpellArea : public CIntObject
|
||||||
{
|
{
|
||||||
@ -116,6 +117,8 @@ class CSpellWindow : public CWindowObject
|
|||||||
void turnPageLeft();
|
void turnPageLeft();
|
||||||
void turnPageRight();
|
void turnPageRight();
|
||||||
|
|
||||||
|
void onVideoPlaybackFinished() override;
|
||||||
|
|
||||||
bool openOnBattleSpells;
|
bool openOnBattleSpells;
|
||||||
std::function<void(SpellID)> onSpellSelect; //external processing of selected spell
|
std::function<void(SpellID)> onSpellSelect; //external processing of selected spell
|
||||||
|
|
||||||
|
@ -1670,22 +1670,27 @@ VideoWindow::VideoWindow(const VideoPath & video, const ImagePath & rim, bool sh
|
|||||||
if(!rim.empty())
|
if(!rim.empty())
|
||||||
{
|
{
|
||||||
setBackground(rim);
|
setBackground(rim);
|
||||||
videoPlayer = std::make_shared<VideoWidgetOnce>(Point(80, 186), video, true, [this](){ exit(false); });
|
videoPlayer = std::make_shared<VideoWidgetOnce>(Point(80, 186), video, true, this);
|
||||||
pos = center(Rect(0, 0, 800, 600));
|
pos = center(Rect(0, 0, 800, 600));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
blackBackground = std::make_shared<GraphicalPrimitiveCanvas>(Rect(0, 0, GH.screenDimensions().x, GH.screenDimensions().y));
|
blackBackground = std::make_shared<GraphicalPrimitiveCanvas>(Rect(0, 0, GH.screenDimensions().x, GH.screenDimensions().y));
|
||||||
videoPlayer = std::make_shared<VideoWidgetOnce>(Point(0, 0), video, true, scaleFactor, [this](){ exit(false); });
|
videoPlayer = std::make_shared<VideoWidgetOnce>(Point(0, 0), video, true, scaleFactor, this);
|
||||||
pos = center(Rect(0, 0, videoPlayer->pos.w, videoPlayer->pos.h));
|
pos = center(Rect(0, 0, videoPlayer->pos.w, videoPlayer->pos.h));
|
||||||
blackBackground->addBox(Point(0, 0), Point(pos.x, pos.y), Colors::BLACK);
|
blackBackground->addBox(Point(0, 0), Point(pos.x, pos.y), Colors::BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(backgroundAroundWindow)
|
if(backgroundAroundWindow)
|
||||||
backgroundAroundWindow->pos.moveTo(Point(0, 0));
|
backgroundAroundWindow->pos.moveTo(Point(0, 0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoWindow::onVideoPlaybackFinished()
|
||||||
|
{
|
||||||
|
exit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VideoWindow::exit(bool skipped)
|
void VideoWindow::exit(bool skipped)
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "CWindowObject.h"
|
#include "CWindowObject.h"
|
||||||
#include "../lib/ResourceSet.h"
|
#include "../lib/ResourceSet.h"
|
||||||
#include "../widgets/Images.h"
|
#include "../widgets/Images.h"
|
||||||
|
#include "../widgets/IVideoHolder.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -509,7 +510,7 @@ public:
|
|||||||
CThievesGuildWindow(const CGObjectInstance * _owner);
|
CThievesGuildWindow(const CGObjectInstance * _owner);
|
||||||
};
|
};
|
||||||
|
|
||||||
class VideoWindow : public CWindowObject
|
class VideoWindow : public CWindowObject, public IVideoHolder
|
||||||
{
|
{
|
||||||
std::shared_ptr<VideoWidgetOnce> videoPlayer;
|
std::shared_ptr<VideoWidgetOnce> videoPlayer;
|
||||||
std::shared_ptr<CFilledTexture> backgroundAroundWindow;
|
std::shared_ptr<CFilledTexture> backgroundAroundWindow;
|
||||||
@ -517,6 +518,7 @@ class VideoWindow : public CWindowObject
|
|||||||
|
|
||||||
std::function<void(bool)> closeCb;
|
std::function<void(bool)> closeCb;
|
||||||
|
|
||||||
|
void onVideoPlaybackFinished() override;
|
||||||
void exit(bool skipped);
|
void exit(bool skipped);
|
||||||
public:
|
public:
|
||||||
VideoWindow(const VideoPath & video, const ImagePath & rim, bool showBackground, float scaleFactor, const std::function<void(bool)> & closeCb);
|
VideoWindow(const VideoPath & video, const ImagePath & rim, bool showBackground, float scaleFactor, const std::function<void(bool)> & closeCb);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user