VideoWidget.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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 "../CGameInfo.h"
  14. #include "../gui/CGuiHandler.h"
  15. #include "../media/ISoundPlayer.h"
  16. #include "../media/IVideoPlayer.h"
  17. #include "../render/Canvas.h"
  18. #include "../../lib/filesystem/Filesystem.h"
  19. VideoWidgetBase::VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio)
  20. : VideoWidgetBase(position, video, playAudio, 1.0)
  21. {
  22. }
  23. VideoWidgetBase::VideoWidgetBase(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor)
  24. : playAudio(playAudio), scaleFactor(scaleFactor)
  25. {
  26. addUsedEvents(TIME);
  27. pos += position;
  28. playVideo(video);
  29. }
  30. VideoWidgetBase::~VideoWidgetBase() = default;
  31. void VideoWidgetBase::playVideo(const VideoPath & fileToPlay)
  32. {
  33. OBJECT_CONSTRUCTION;
  34. using SubTitlePath = ResourcePathTempl<EResType::SUBTITLE>;
  35. SubTitlePath subTitlePath = fileToPlay.toType<EResType::SUBTITLE>();
  36. SubTitlePath subTitlePathVideoDir = subTitlePath.addPrefix("VIDEO/");
  37. if(CResourceHandler::get()->existsResource(subTitlePath))
  38. {
  39. auto rawData = CResourceHandler::get()->load(subTitlePath)->readAll();
  40. srtContent = std::string(reinterpret_cast<char *>(rawData.first.get()), rawData.second);
  41. }
  42. if(CResourceHandler::get()->existsResource(subTitlePathVideoDir))
  43. {
  44. auto rawData = CResourceHandler::get()->load(subTitlePathVideoDir)->readAll();
  45. srtContent = std::string(reinterpret_cast<char *>(rawData.first.get()), rawData.second);
  46. }
  47. videoInstance = CCS->videoh->open(fileToPlay, scaleFactor);
  48. if (videoInstance)
  49. {
  50. pos.w = videoInstance->size().x;
  51. pos.h = videoInstance->size().y;
  52. subTitle = std::make_unique<CMultiLineLabel>(Rect(0, (pos.h / 5) * 4, pos.w, pos.h / 5), EFonts::FONT_HIGH_SCORE, ETextAlignment::CENTER, Colors::WHITE, "");
  53. }
  54. if (playAudio)
  55. {
  56. loadAudio(fileToPlay);
  57. if (isActive())
  58. startAudio();
  59. }
  60. }
  61. void VideoWidgetBase::show(Canvas & to)
  62. {
  63. if(videoInstance)
  64. videoInstance->show(pos.topLeft(), to);
  65. if(subTitle)
  66. subTitle->showAll(to);
  67. }
  68. void VideoWidgetBase::loadAudio(const VideoPath & fileToPlay)
  69. {
  70. if (!playAudio)
  71. return;
  72. audioData = CCS->videoh->getAudio(fileToPlay);
  73. }
  74. void VideoWidgetBase::startAudio()
  75. {
  76. if(audioData.first == nullptr)
  77. return;
  78. audioHandle = CCS->soundh->playSound(audioData);
  79. if(audioHandle != -1)
  80. {
  81. CCS->soundh->setCallback(
  82. audioHandle,
  83. [this]()
  84. {
  85. this->audioHandle = -1;
  86. }
  87. );
  88. }
  89. }
  90. void VideoWidgetBase::stopAudio()
  91. {
  92. if(audioHandle != -1)
  93. {
  94. CCS->soundh->resetCallback(audioHandle);
  95. CCS->soundh->stopSound(audioHandle);
  96. audioHandle = -1;
  97. }
  98. }
  99. std::string VideoWidgetBase::getSubTitleLine(double timestamp)
  100. {
  101. if(srtContent.empty())
  102. return "";
  103. std::regex exp("^\\s*(\\d+:\\d+:\\d+,\\d+)[^\\S\\n]+-->[^\\S\\n]+(\\d+:\\d+:\\d+,\\d+)((?:\\n(?!\\d+:\\d+:\\d+,\\d+\\b|\\n+\\d+$).*)*)", std::regex::multiline);
  104. std::smatch res;
  105. std::string::const_iterator searchStart(srtContent.cbegin());
  106. while (std::regex_search(searchStart, srtContent.cend(), res, exp))
  107. {
  108. std::vector<std::string> timestamp1Str;
  109. boost::split(timestamp1Str, static_cast<std::string>(res[1]), boost::is_any_of(":,"));
  110. std::vector<std::string> timestamp2Str;
  111. boost::split(timestamp2Str, static_cast<std::string>(res[2]), boost::is_any_of(":,"));
  112. double timestamp1 = std::stoi(timestamp1Str[0]) * 3600 + std::stoi(timestamp1Str[1]) * 60 + std::stoi(timestamp1Str[2]) + (std::stoi(timestamp1Str[3]) / 1000.0);
  113. double timestamp2 = std::stoi(timestamp2Str[0]) * 3600 + std::stoi(timestamp2Str[1]) * 60 + std::stoi(timestamp2Str[2]) + (std::stoi(timestamp2Str[3]) / 1000.0);
  114. std::string text = res[3];
  115. text.erase(0, text.find_first_not_of("\r\n\t "));
  116. if(timestamp > timestamp1 && timestamp < timestamp2)
  117. return text;
  118. searchStart = res.suffix().first;
  119. }
  120. return "";
  121. }
  122. void VideoWidgetBase::activate()
  123. {
  124. CIntObject::activate();
  125. startAudio();
  126. }
  127. void VideoWidgetBase::deactivate()
  128. {
  129. CIntObject::deactivate();
  130. stopAudio();
  131. }
  132. void VideoWidgetBase::showAll(Canvas & to)
  133. {
  134. if(videoInstance)
  135. videoInstance->show(pos.topLeft(), to);
  136. if(subTitle)
  137. subTitle->showAll(to);
  138. }
  139. void VideoWidgetBase::tick(uint32_t msPassed)
  140. {
  141. if(videoInstance)
  142. {
  143. videoInstance->tick(msPassed);
  144. if(videoInstance->videoEnded())
  145. {
  146. videoInstance.reset();
  147. stopAudio();
  148. onPlaybackFinished();
  149. }
  150. }
  151. if(subTitle && videoInstance)
  152. subTitle->setText(getSubTitleLine(videoInstance->timeStamp()));
  153. }
  154. VideoWidget::VideoWidget(const Point & position, const VideoPath & prologue, const VideoPath & looped, bool playAudio)
  155. : VideoWidgetBase(position, prologue, playAudio)
  156. , loopedVideo(looped)
  157. {
  158. }
  159. VideoWidget::VideoWidget(const Point & position, const VideoPath & looped, bool playAudio)
  160. : VideoWidgetBase(position, looped, playAudio)
  161. , loopedVideo(looped)
  162. {
  163. }
  164. void VideoWidget::onPlaybackFinished()
  165. {
  166. playVideo(loopedVideo);
  167. }
  168. VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, const std::function<void()> & callback)
  169. : VideoWidgetBase(position, video, playAudio)
  170. , callback(callback)
  171. {
  172. }
  173. VideoWidgetOnce::VideoWidgetOnce(const Point & position, const VideoPath & video, bool playAudio, float scaleFactor, const std::function<void()> & callback)
  174. : VideoWidgetBase(position, video, playAudio, scaleFactor)
  175. , callback(callback)
  176. {
  177. }
  178. void VideoWidgetOnce::onPlaybackFinished()
  179. {
  180. callback();
  181. }