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:
parent
02da800151
commit
540bd16e7b
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user