VideoWidget.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * TextControls.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "VideoWidget.h"
  12. #include "TextControls.h"
  13. #include "IVideoHolder.h"
  14. #include "../CGameInfo.h"
  15. #include "../gui/CGuiHandler.h"
  16. #include "../media/ISoundPlayer.h"
  17. #include "../media/IVideoPlayer.h"
  18. #include "../render/Canvas.h"
  19. #include "../render/IScreenHandler.h"
  20. #include "../../lib/filesystem/Filesystem.h"
  21. VideoWidgetBase::VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio)
  22. : VideoWidgetBase(position, video, playAudio, 1.0)
  23. {
  24. }
  25. VideoWidgetBase::VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor)
  26. : playAudio(playAudio), scaleFactor(scaleFactor)
  27. {
  28. addUsedEvents(TIME);
  29. pos += position;
  30. playVideo(video);
  31. }
  32. VideoWidgetBase::~VideoWidgetBase() = default;
  33. void VideoWidgetBase::playVideo(const VideoPath & fileToPlay)
  34. {
  35. OBJECT_CONSTRUCTION;
  36. JsonPath subTitlePath = fileToPlay.toType<EResType::JSON>();
  37. JsonPath subTitlePathVideoDir = subTitlePath.addPrefix("VIDEO/");
  38. if(CResourceHandler::get()->existsResource(subTitlePath))
  39. subTitleData = JsonNode(subTitlePath);
  40. else if(CResourceHandler::get()->existsResource(subTitlePathVideoDir))
  41. subTitleData = JsonNode(subTitlePathVideoDir);
  42. float preScaleFactor = 1;
  43. VideoPath videoFile = fileToPlay;
  44. if(GH.screenHandler().getScalingFactor() > 1)
  45. {
  46. std::vector<int> factorsToCheck = {GH.screenHandler().getScalingFactor(), 4, 3, 2};
  47. for(auto factorToCheck : factorsToCheck)
  48. {
  49. std::string name = boost::algorithm::to_upper_copy(videoFile.getName());
  50. boost::replace_all(name, "VIDEO/", std::string("VIDEO") + std::to_string(factorToCheck) + std::string("X/"));
  51. auto p = VideoPath::builtin(name).addPrefix("VIDEO" + std::to_string(factorToCheck) + "X/");
  52. if(CResourceHandler::get()->existsResource(p))
  53. {
  54. preScaleFactor = 1.0 / static_cast<float>(factorToCheck);
  55. videoFile = p;
  56. break;
  57. }
  58. }
  59. }
  60. videoInstance = CCS->videoh->open(videoFile, scaleFactor * preScaleFactor);
  61. if (videoInstance)
  62. {
  63. pos.w = videoInstance->size().x;
  64. pos.h = videoInstance->size().y;
  65. if(!subTitleData.isNull())
  66. subTitle = std::make_unique<CMultiLineLabel>(Rect(0, (pos.h / 5) * 4, pos.w, pos.h / 5), EFonts::FONT_HIGH_SCORE, ETextAlignment::CENTER, Colors::WHITE);
  67. }
  68. if (playAudio)
  69. {
  70. loadAudio(fileToPlay);
  71. if (isActive())
  72. startAudio();
  73. }
  74. }
  75. void VideoWidgetBase::show(Canvas & to)
  76. {
  77. if(videoInstance)
  78. videoInstance->show(pos.topLeft(), to);
  79. if(subTitle)
  80. subTitle->showAll(to);
  81. }
  82. void VideoWidgetBase::loadAudio(const VideoPath & fileToPlay)
  83. {
  84. if (!playAudio)
  85. return;
  86. audioData = CCS->videoh->getAudio(fileToPlay);
  87. }
  88. void VideoWidgetBase::startAudio()
  89. {
  90. if(audioData.first == nullptr)
  91. return;
  92. audioHandle = CCS->soundh->playSound(audioData);
  93. if(audioHandle != -1)
  94. {
  95. CCS->soundh->setCallback(
  96. audioHandle,
  97. [this]()
  98. {
  99. this->audioHandle = -1;
  100. }
  101. );
  102. }
  103. }
  104. void VideoWidgetBase::stopAudio()
  105. {
  106. if(audioHandle != -1)
  107. {
  108. CCS->soundh->resetCallback(audioHandle);
  109. CCS->soundh->stopSound(audioHandle);
  110. audioHandle = -1;
  111. }
  112. }
  113. std::string VideoWidgetBase::getSubTitleLine(double timestamp)
  114. {
  115. if(subTitleData.isNull())
  116. return {};
  117. for(auto & segment : subTitleData.Vector())
  118. if(timestamp > segment["timeStart"].Float() && timestamp < segment["timeEnd"].Float())
  119. return segment["text"].String();
  120. return {};
  121. }
  122. void VideoWidgetBase::activate()
  123. {
  124. CIntObject::activate();
  125. if(audioHandle != -1)
  126. CCS->soundh->resumeSound(audioHandle);
  127. else
  128. startAudio();
  129. if(videoInstance)
  130. videoInstance->activate();
  131. }
  132. void VideoWidgetBase::deactivate()
  133. {
  134. CIntObject::deactivate();
  135. CCS->soundh->pauseSound(audioHandle);
  136. if(videoInstance)
  137. videoInstance->deactivate();
  138. }
  139. void VideoWidgetBase::showAll(Canvas & to)
  140. {
  141. if(videoInstance)
  142. videoInstance->show(pos.topLeft(), to);
  143. if(subTitle)
  144. subTitle->showAll(to);
  145. }
  146. void VideoWidgetBase::tick(uint32_t msPassed)
  147. {
  148. if(videoInstance)
  149. {
  150. videoInstance->tick(msPassed);
  151. if(!videoInstance->videoEnded() && subTitle)
  152. subTitle->setText(getSubTitleLine(videoInstance->timeStamp()));
  153. if(videoInstance->videoEnded())
  154. {
  155. videoInstance.reset();
  156. stopAudio();
  157. onPlaybackFinished();
  158. // WARNING: onPlaybackFinished call may destoy `this`. Make sure that this is the very last operation in this method!
  159. }
  160. }
  161. }
  162. VideoWidget::VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped, bool playAudio)
  163. : VideoWidgetBase(position, prologue, playAudio)
  164. , loopedVideo(looped)
  165. {
  166. }
  167. VideoWidget::VideoWidget(const Point & position, const VideoPath & looped, bool playAudio)
  168. : VideoWidgetBase(position, looped, playAudio)
  169. , loopedVideo(looped)
  170. {
  171. }
  172. void VideoWidget::onPlaybackFinished()
  173. {
  174. playVideo(loopedVideo);
  175. }
  176. VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, IVideoHolder * owner)
  177. : VideoWidgetBase(position, video, playAudio)
  178. , owner(owner)
  179. {
  180. }
  181. VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor, IVideoHolder * owner)
  182. : VideoWidgetBase(position, video, playAudio, scaleFactor)
  183. , owner(owner)
  184. {
  185. }
  186. void VideoWidgetOnce::onPlaybackFinished()
  187. {
  188. owner->onVideoPlaybackFinished();
  189. }