1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Fixed video widget playback

This commit is contained in:
Ivan Savenko 2024-05-15 16:34:23 +00:00
parent 02da800151
commit 540bd16e7b
12 changed files with 171 additions and 63 deletions

View File

@ -709,7 +709,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
auto resources = getResources(br);
description = std::make_shared<CTextBox>(resources.resultText.toString(), Rect(69, 203, 330, 68), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
videoPlayer = std::make_shared<VideoWidget>(Point(107, 70), resources.prologueVideo, resources.loopedVideo);
videoPlayer = std::make_shared<VideoWidget>(Point(107, 70), resources.prologueVideo, resources.loopedVideo, false);
CCS->musich->playMusic(resources.musicName, false, true);
}

View File

@ -145,7 +145,7 @@ void CCampaignScreen::CCampaignButton::hover(bool on)
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
if (on && !videoPath.empty())
videoPlayer = std::make_shared<VideoWidget>(Point(), videoPath);
videoPlayer = std::make_shared<VideoWidget>(Point(), videoPath, false);
else
videoPlayer.reset();

View File

@ -229,7 +229,8 @@ CHighScoreInputScreen::CHighScoreInputScreen(bool won, HighScoreCalculation calc
if(won)
{
videoPlayer = std::make_shared<VideoWidget>(Point(30, 120), VideoPath::builtin("HSANIM.SMK"), VideoPath::builtin("HSLOOP.SMK"));
videoPlayer = std::make_shared<VideoWidget>(Point(0, 0), VideoPath::builtin("HSANIM.SMK"), VideoPath::builtin("HSLOOP.SMK"), true);
int border = 100;
int textareaW = ((pos.w - 2 * border) / 4);
@ -246,7 +247,7 @@ CHighScoreInputScreen::CHighScoreInputScreen(bool won, HighScoreCalculation calc
}
else
{
videoPlayer = std::make_shared<VideoWidget>(Point(30, 120), VideoPath::builtin("HSANIM.SMK"), VideoPath::builtin("LOSEGAME.SMK"));
videoPlayer = std::make_shared<VideoWidgetOnce>(Point(0, 0), VideoPath::builtin("LOSEGAME.SMK"), true, [this](){close();});
CCS->musich->playMusic(AudioPath::builtin("music/UltimateLose"), false, true);
}
}
@ -291,6 +292,11 @@ int CHighScoreInputScreen::addEntry(std::string text) {
return pos;
}
void CHighScoreInputScreen::show(Canvas & to)
{
CWindowObject::showAll(to);
}
void CHighScoreInputScreen::clickPressed(const Point & cursorPosition)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;

View File

@ -15,7 +15,7 @@ class CLabel;
class CMultiLineLabel;
class CAnimImage;
class CTextInput;
class VideoWidget;
class VideoWidgetBase;
class TransparentFilledRectangle;
@ -94,7 +94,7 @@ class CHighScoreInputScreen : public CWindowObject
std::vector<std::shared_ptr<CMultiLineLabel>> texts;
std::shared_ptr<CHighScoreInput> input;
std::shared_ptr<TransparentFilledRectangle> background;
std::shared_ptr<VideoWidget> videoPlayer;
std::shared_ptr<VideoWidgetBase> videoPlayer;
bool won;
HighScoreCalculation calc;
@ -105,4 +105,5 @@ public:
void clickPressed(const Point & cursorPosition) override;
void keyPressed(EShortcut key) override;
void show(Canvas & to) override;
};

View File

@ -95,7 +95,7 @@ CMenuScreen::CMenuScreen(const JsonNode & configNode)
if(!config["video"].isNull())
{
Point videoPosition(config["video"]["x"].Integer(), config["video"]["y"].Integer());
videoPlayer = std::make_shared<VideoWidget>(videoPosition, VideoPath::fromJson(config["video"]["name"]));
videoPlayer = std::make_shared<VideoWidget>(videoPosition, VideoPath::fromJson(config["video"]["name"]), false);
}
else
tabs->setRedrawParent(true);
@ -110,6 +110,12 @@ std::shared_ptr<CIntObject> CMenuScreen::createTab(size_t index)
return std::make_shared<CMenuEntry>(this, config["items"].Vector()[index]);
}
void CMenuScreen::show(Canvas & to)
{
// TODO: avoid excessive redraws
CIntObject::showAll(to);
}
void CMenuScreen::activate()
{
CCS->musich->playMusic(AudioPath::builtin("Music/MainMenu"), true, true);

View File

@ -59,6 +59,7 @@ public:
CMenuScreen(const JsonNode & configNode);
void activate() override;
void show(Canvas & to);
void switchToTab(size_t index);
void switchToTab(std::string name);

View File

@ -29,7 +29,7 @@ CPrologEpilogVideo::CPrologEpilogVideo(CampaignScenarioPrologEpilog _spe, std::f
pos = center(Rect(0, 0, 800, 600));
updateShadow();
videoPlayer = std::make_shared<VideoWidget>(Point(30, 120), spe.prologVideo);
videoPlayer = std::make_shared<VideoWidget>(Point(0, 0), spe.prologVideo, true);
//some videos are 800x600 in size while some are 800x400
if (videoPlayer->pos.h == 400)

View File

@ -469,7 +469,7 @@ std::pair<std::unique_ptr<ui8 []>, si64> CAudioInstance::extractAudio(const Vide
// Workaround for lack of resampler
// Currently, ffmpeg on conan systems is built without sws resampler
// Because of that, and because wav format does not supports 'planar' formats from ffmpeg
// we need to de-planarize it and convert to "normal" (non-planar / interleaved) steram
// we need to de-planarize it and convert to "normal" (non-planar / interleaved) stream
samples.reserve(samples.size() + bytesToRead);
for (int sm = 0; sm < frame->nb_samples; ++sm)
for (int ch = 0; ch < numChannels; ++ch)
@ -592,6 +592,7 @@ std::unique_ptr<IVideoInstance> CVideoPlayer::open(const VideoPath & name, bool
result->openInput(name);
result->openVideo();
result->prepareOutput(scaleToScreen, false);
result->loadNextFrame(); // prepare 1st frame
return result;
}

View File

@ -12,72 +12,137 @@
#include "../CGameInfo.h"
#include "../gui/CGuiHandler.h"
#include "../gui/WindowHandler.h"
#include "../media/ISoundPlayer.h"
#include "../media/IVideoPlayer.h"
#include "../render/Canvas.h"
VideoWidget::VideoWidget(const Point & position, const VideoPath & looped)
: VideoWidget(position, VideoPath(), looped)
VideoWidgetBase::VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio)
: playAudio(playAudio)
{
addUsedEvents(TIME);
pos += position;
playVideo(video);
}
VideoWidget::VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped)
: current(prologue)
, next(looped)
, videoSoundHandle(-1)
VideoWidgetBase::~VideoWidgetBase() = default;
void VideoWidgetBase::playVideo(const VideoPath & fileToPlay)
{
if(current.empty())
videoInstance = CCS->videoh->open(looped, false);
else
videoInstance = CCS->videoh->open(current, false);
}
VideoWidget::~VideoWidget() = default;
void VideoWidget::show(Canvas & to)
{
if(videoInstance)
videoInstance->show(pos.topLeft(), to);
}
void VideoWidget::activate()
{
// if(videoInstance)
// videoInstance->playAudio();
if(videoSoundHandle != -1)
videoInstance = CCS->videoh->open(fileToPlay, false);
if (videoInstance)
{
CCS->soundh->setCallback(
videoSoundHandle,
[this]()
{
if(GH.windows().isTopWindow(this))
this->videoSoundHandle = -1;
}
);
pos.w = videoInstance->size().x;
pos.h = videoInstance->size().y;
}
if (playAudio)
{
loadAudio(fileToPlay);
if (isActive())
startAudio();
}
}
void VideoWidget::deactivate()
{
CCS->soundh->stopSound(videoSoundHandle);
}
void VideoWidget::showAll(Canvas & to)
void VideoWidgetBase::show(Canvas & to)
{
if(videoInstance)
videoInstance->show(pos.topLeft(), to);
}
void VideoWidget::tick(uint32_t msPassed)
void VideoWidgetBase::loadAudio(const VideoPath & fileToPlay)
{
if (!playAudio)
return;
audioData = CCS->videoh->getAudio(fileToPlay);
}
void VideoWidgetBase::startAudio()
{
if(audioData.first == nullptr)
return;
audioHandle = CCS->soundh->playSound(audioData);
if(audioHandle != -1)
{
CCS->soundh->setCallback(
audioHandle,
[this]()
{
this->audioHandle = -1;
}
);
}
}
void VideoWidgetBase::stopAudio()
{
if(audioHandle != -1)
{
CCS->soundh->resetCallback(audioHandle);
CCS->soundh->stopSound(audioHandle);
audioHandle = -1;
}
}
void VideoWidgetBase::activate()
{
CIntObject::activate();
startAudio();
}
void VideoWidgetBase::deactivate()
{
CIntObject::deactivate();
stopAudio();
}
void VideoWidgetBase::showAll(Canvas & to)
{
if(videoInstance)
videoInstance->show(pos.topLeft(), to);
}
void VideoWidgetBase::tick(uint32_t msPassed)
{
if(videoInstance)
{
videoInstance->tick(msPassed);
if(videoInstance->videoEnded())
videoInstance = CCS->videoh->open(next, false);
{
videoInstance.reset();
stopAudio();
onPlaybackFinished();
}
}
}
VideoWidget::VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped, bool playAudio)
: VideoWidgetBase(position, prologue, playAudio)
, loopedVideo(looped)
{
}
VideoWidget::VideoWidget(const Point & position, const VideoPath & looped, bool playAudio)
: VideoWidgetBase(position, looped, playAudio)
, loopedVideo(looped)
{
}
void VideoWidget::onPlaybackFinished()
{
playVideo(loopedVideo);
}
VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, const std::function<void()> & callback)
: VideoWidgetBase(position, video, playAudio)
, callback(callback)
{
}
void VideoWidgetOnce::onPlaybackFinished()
{
callback();
}

View File

@ -15,23 +15,51 @@
class IVideoInstance;
class VideoWidget final : public CIntObject
class VideoWidgetBase : public CIntObject
{
std::unique_ptr<IVideoInstance> videoInstance;
VideoPath current;
VideoPath next;
std::pair<std::unique_ptr<ui8[]>, si64> audioData = {nullptr, 0};
int audioHandle = -1;
bool playAudio = false;
int videoSoundHandle;
void loadAudio(const VideoPath & file);
void startAudio();
void stopAudio();
protected:
VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio);
virtual void onPlaybackFinished() = 0;
void playVideo(const VideoPath & video);
public:
VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped);
VideoWidget(const Point & position, const VideoPath & looped);
~VideoWidget();
~VideoWidgetBase();
void activate() override;
void deactivate() override;
void show(Canvas & to) override;
void showAll(Canvas & to) override;
void tick(uint32_t msPassed) override;
void setPlaybackFinishedCallback(std::function<void()>);
};
class VideoWidget final: public VideoWidgetBase
{
VideoPath loopedVideo;
void onPlaybackFinished() final;
public:
VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped, bool playAudio);
VideoWidget(const Point & position, const VideoPath & looped, bool playAudio);
};
class VideoWidgetOnce final: public VideoWidgetBase
{
std::function<void()> callback;
void onPlaybackFinished() final;
public:
VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, const std::function<void()> & callback);
};

View File

@ -57,7 +57,7 @@ void CTutorialWindow::setContent()
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
auto video = VideoPath::builtin("tutorial/" + videos[page]);
videoPlayer = std::make_shared<VideoWidget>(Point(30, 120), video);
videoPlayer = std::make_shared<VideoWidget>(Point(30, 120), video, false);
buttonLeft->block(page<1);
buttonRight->block(page>videos.size() - 2);

View File

@ -515,11 +515,11 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
recruit->block(true);
}
if(LOCPLINT->castleInt)
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), LOCPLINT->castleInt->town->town->clientInfo.tavernVideo);
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), LOCPLINT->castleInt->town->town->clientInfo.tavernVideo, false);
else if(const auto * townObj = dynamic_cast<const CGTownInstance *>(TavernObj))
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), townObj->town->clientInfo.tavernVideo);
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), townObj->town->clientInfo.tavernVideo, false);
else
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), VideoPath::builtin("TAVERN.BIK"));
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), VideoPath::builtin("TAVERN.BIK"), false);
addInvite();
}