PlaybackManager.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Format.h>
  7. #include <LibCore/Timer.h>
  8. #include <LibVideo/MatroskaReader.h>
  9. #include <LibVideo/VP9/Decoder.h>
  10. #include "MatroskaDemuxer.h"
  11. #include "PlaybackManager.h"
  12. namespace Video {
  13. DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> PlaybackManager::from_file(Core::Object& event_handler, StringView filename)
  14. {
  15. NonnullOwnPtr<Demuxer> demuxer = TRY(MatroskaDemuxer::from_file(filename));
  16. auto video_tracks = demuxer->get_tracks_for_type(TrackType::Video);
  17. if (video_tracks.is_empty())
  18. return DecoderError::with_description(DecoderErrorCategory::Invalid, "No video track is present"sv);
  19. auto track = video_tracks[0];
  20. dbgln_if(PLAYBACK_MANAGER_DEBUG, "Selecting video track number {}", track.identifier());
  21. return make<PlaybackManager>(event_handler, demuxer, track, make<VP9::Decoder>());
  22. }
  23. PlaybackManager::PlaybackManager(Core::Object& event_handler, NonnullOwnPtr<Demuxer>& demuxer, Track video_track, NonnullOwnPtr<VideoDecoder>&& decoder)
  24. : m_event_handler(event_handler)
  25. , m_main_loop(Core::EventLoop::current())
  26. , m_demuxer(move(demuxer))
  27. , m_selected_video_track(video_track)
  28. , m_decoder(move(decoder))
  29. , m_frame_queue(make<VideoFrameQueue>())
  30. , m_present_timer(Core::Timer::construct())
  31. , m_decode_timer(Core::Timer::construct())
  32. {
  33. m_present_timer->set_single_shot(true);
  34. m_present_timer->set_interval(0);
  35. m_present_timer->on_timeout = [&] { update_presented_frame(); };
  36. m_decode_timer->set_single_shot(true);
  37. m_decode_timer->set_interval(0);
  38. m_decode_timer->on_timeout = [&] { on_decode_timer(); };
  39. }
  40. void PlaybackManager::set_playback_status(PlaybackStatus status)
  41. {
  42. if (status != m_status) {
  43. auto old_status = m_status;
  44. m_status = status;
  45. dbgln_if(PLAYBACK_MANAGER_DEBUG, "Set playback status from {} to {}", playback_status_to_string(old_status), playback_status_to_string(m_status));
  46. if (status == PlaybackStatus::Playing) {
  47. if (old_status == PlaybackStatus::Stopped || old_status == PlaybackStatus::Corrupted) {
  48. restart_playback();
  49. m_frame_queue->clear();
  50. m_skipped_frames = 0;
  51. }
  52. m_last_present_in_real_time = Time::now_monotonic();
  53. m_present_timer->start(0);
  54. } else {
  55. m_last_present_in_media_time = current_playback_time();
  56. m_last_present_in_real_time = Time::zero();
  57. m_present_timer->stop();
  58. }
  59. m_main_loop.post_event(m_event_handler, make<PlaybackStatusChangeEvent>(status, old_status));
  60. }
  61. }
  62. void PlaybackManager::resume_playback()
  63. {
  64. set_playback_status(PlaybackStatus::Playing);
  65. }
  66. void PlaybackManager::pause_playback()
  67. {
  68. set_playback_status(PlaybackStatus::Paused);
  69. }
  70. bool PlaybackManager::prepare_next_frame()
  71. {
  72. if (m_next_frame.has_value())
  73. return true;
  74. if (m_frame_queue->is_empty())
  75. return false;
  76. auto frame_item = m_frame_queue->dequeue();
  77. m_next_frame.emplace(move(frame_item));
  78. m_decode_timer->start(0);
  79. return true;
  80. }
  81. Time PlaybackManager::current_playback_time()
  82. {
  83. if (is_playing())
  84. return m_last_present_in_media_time + (Time::now_monotonic() - m_last_present_in_real_time);
  85. return m_last_present_in_media_time;
  86. }
  87. Time PlaybackManager::duration()
  88. {
  89. return m_demuxer->duration();
  90. }
  91. void PlaybackManager::on_decoder_error(DecoderError error)
  92. {
  93. dbgln("Playback error encountered: {}", error.string_literal());
  94. switch (error.category()) {
  95. case DecoderErrorCategory::EndOfStream:
  96. set_playback_status(PlaybackStatus::Stopped);
  97. break;
  98. default:
  99. set_playback_status(PlaybackStatus::Corrupted);
  100. m_main_loop.post_event(m_event_handler, make<DecoderErrorEvent>(move(error)));
  101. break;
  102. }
  103. }
  104. void PlaybackManager::update_presented_frame()
  105. {
  106. bool out_of_queued_frames = false;
  107. Optional<FrameQueueItem> frame_item_to_display;
  108. while (true) {
  109. out_of_queued_frames = out_of_queued_frames || !prepare_next_frame();
  110. if (out_of_queued_frames)
  111. break;
  112. VERIFY(m_next_frame.has_value());
  113. if (m_next_frame->is_error() || m_next_frame->timestamp() > current_playback_time())
  114. break;
  115. if (frame_item_to_display.has_value()) {
  116. dbgln_if(PLAYBACK_MANAGER_DEBUG, "At {}ms: Dropped {} in favor of {}", current_playback_time().to_milliseconds(), frame_item_to_display->debug_string(), m_next_frame->debug_string());
  117. m_skipped_frames++;
  118. }
  119. frame_item_to_display = m_next_frame.release_value();
  120. }
  121. if (!out_of_queued_frames && frame_item_to_display.has_value()) {
  122. m_main_loop.post_event(m_event_handler, make<VideoFramePresentEvent>(frame_item_to_display->bitmap()));
  123. m_last_present_in_media_time = current_playback_time();
  124. m_last_present_in_real_time = Time::now_monotonic();
  125. frame_item_to_display.clear();
  126. }
  127. if (frame_item_to_display.has_value()) {
  128. VERIFY(!m_next_frame.has_value());
  129. m_next_frame = frame_item_to_display;
  130. dbgln_if(PLAYBACK_MANAGER_DEBUG, "Set next frame back to dequeued item {}", m_next_frame->debug_string());
  131. }
  132. if (!is_playing())
  133. return;
  134. if (!out_of_queued_frames) {
  135. if (m_next_frame->is_error()) {
  136. on_decoder_error(m_next_frame->release_error());
  137. m_next_frame.clear();
  138. return;
  139. }
  140. auto frame_time_ms = (m_next_frame->timestamp() - current_playback_time()).to_milliseconds();
  141. VERIFY(frame_time_ms <= NumericLimits<int>::max());
  142. dbgln_if(PLAYBACK_MANAGER_DEBUG, "Time until next frame is {}ms", frame_time_ms);
  143. m_present_timer->start(max(static_cast<int>(frame_time_ms), 0));
  144. return;
  145. }
  146. set_playback_status(PlaybackStatus::Buffering);
  147. m_decode_timer->start(0);
  148. }
  149. void PlaybackManager::restart_playback()
  150. {
  151. m_last_present_in_media_time = Time::zero();
  152. m_last_present_in_real_time = Time::zero();
  153. auto result = m_demuxer->seek_to_most_recent_keyframe(m_selected_video_track, 0);
  154. if (result.is_error())
  155. on_decoder_error(result.release_error());
  156. }
  157. void PlaybackManager::post_decoder_error(DecoderError error)
  158. {
  159. m_main_loop.post_event(m_event_handler, make<DecoderErrorEvent>(error));
  160. }
  161. bool PlaybackManager::decode_and_queue_one_sample()
  162. {
  163. if (m_frame_queue->size() >= FRAME_BUFFER_COUNT)
  164. return false;
  165. #if PLAYBACK_MANAGER_DEBUG
  166. auto start_time = Time::now_monotonic();
  167. #endif
  168. #define TRY_OR_ENQUEUE_ERROR(expression) \
  169. ({ \
  170. auto _temporary_result = ((expression)); \
  171. if (_temporary_result.is_error()) { \
  172. dbgln("Enqueued decoder error: {}", _temporary_result.error().string_literal()); \
  173. m_frame_queue->enqueue(FrameQueueItem::error_marker(_temporary_result.release_error())); \
  174. return false; \
  175. } \
  176. _temporary_result.release_value(); \
  177. })
  178. auto frame_sample = TRY_OR_ENQUEUE_ERROR(m_demuxer->get_next_video_sample_for_track(m_selected_video_track));
  179. OwnPtr<VideoFrame> decoded_frame = nullptr;
  180. while (!decoded_frame) {
  181. TRY_OR_ENQUEUE_ERROR(m_decoder->receive_sample(frame_sample->data()));
  182. while (true) {
  183. auto frame_result = m_decoder->get_decoded_frame();
  184. if (frame_result.is_error()) {
  185. if (frame_result.error().category() == DecoderErrorCategory::NeedsMoreInput)
  186. break;
  187. post_decoder_error(frame_result.release_error());
  188. return false;
  189. }
  190. decoded_frame = frame_result.release_value();
  191. VERIFY(decoded_frame);
  192. }
  193. }
  194. auto& cicp = decoded_frame->cicp();
  195. cicp.adopt_specified_values(frame_sample->container_cicp());
  196. cicp.default_code_points_if_unspecified({ ColorPrimaries::BT709, TransferCharacteristics::BT709, MatrixCoefficients::BT709, ColorRange::Studio });
  197. // BT.601, BT.709 and BT.2020 have a similar transfer function to sRGB, so other applications
  198. // (Chromium, VLC) forgo transfer characteristics conversion. We will emulate that behavior by
  199. // handling those as sRGB instead, which causes no transfer function change in the output,
  200. // unless display color management is later implemented.
  201. switch (cicp.transfer_characteristics()) {
  202. case TransferCharacteristics::BT601:
  203. case TransferCharacteristics::BT709:
  204. case TransferCharacteristics::BT2020BitDepth10:
  205. case TransferCharacteristics::BT2020BitDepth12:
  206. cicp.set_transfer_characteristics(TransferCharacteristics::SRGB);
  207. break;
  208. default:
  209. break;
  210. }
  211. auto bitmap = TRY_OR_ENQUEUE_ERROR(decoded_frame->to_bitmap());
  212. m_frame_queue->enqueue(FrameQueueItem::frame(bitmap, frame_sample->timestamp()));
  213. #if PLAYBACK_MANAGER_DEBUG
  214. auto end_time = Time::now_monotonic();
  215. dbgln("Decoding took {}ms", (end_time - start_time).to_milliseconds());
  216. #endif
  217. return true;
  218. }
  219. void PlaybackManager::on_decode_timer()
  220. {
  221. if (!decode_and_queue_one_sample() && is_buffering()) {
  222. set_playback_status(PlaybackStatus::Playing);
  223. return;
  224. }
  225. // Continually decode until buffering is complete
  226. if (is_buffering())
  227. m_decode_timer->start(0);
  228. }
  229. }