Serenity Operating System
at master 654 lines 26 kB view raw
1/* 2 * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Format.h> 8#include <LibCore/Timer.h> 9#include <LibVideo/Containers/Matroska/MatroskaDemuxer.h> 10#include <LibVideo/VP9/Decoder.h> 11 12#include "PlaybackManager.h" 13 14namespace Video { 15 16#define TRY_OR_FATAL_ERROR(expression) \ 17 ({ \ 18 auto&& _fatal_expression = (expression); \ 19 if (_fatal_expression.is_error()) { \ 20 dispatch_fatal_error(_fatal_expression.release_error()); \ 21 return; \ 22 } \ 23 static_assert(!::AK::Detail::IsLvalueReference<decltype(_fatal_expression.release_value())>, \ 24 "Do not return a reference from a fallible expression"); \ 25 _fatal_expression.release_value(); \ 26 }) 27 28DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> PlaybackManager::from_file(Core::Object& event_handler, StringView filename) 29{ 30 NonnullOwnPtr<Demuxer> demuxer = TRY(Matroska::MatroskaDemuxer::from_file(filename)); 31 auto video_tracks = TRY(demuxer->get_tracks_for_type(TrackType::Video)); 32 if (video_tracks.is_empty()) 33 return DecoderError::with_description(DecoderErrorCategory::Invalid, "No video track is present"sv); 34 auto track = video_tracks[0]; 35 36 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Selecting video track number {}", track.identifier()); 37 38 return make<PlaybackManager>(event_handler, demuxer, track, make<VP9::Decoder>()); 39} 40 41PlaybackManager::PlaybackManager(Core::Object& event_handler, NonnullOwnPtr<Demuxer>& demuxer, Track video_track, NonnullOwnPtr<VideoDecoder>&& decoder) 42 : m_event_handler(event_handler) 43 , m_main_loop(Core::EventLoop::current()) 44 , m_demuxer(move(demuxer)) 45 , m_selected_video_track(video_track) 46 , m_decoder(move(decoder)) 47 , m_frame_queue(make<VideoFrameQueue>()) 48 , m_playback_handler(make<StartingStateHandler>(*this, false)) 49{ 50 m_present_timer = Core::Timer::create_single_shot(0, [&] { timer_callback(); }).release_value_but_fixme_should_propagate_errors(); 51 m_decode_timer = Core::Timer::create_single_shot(0, [&] { on_decode_timer(); }).release_value_but_fixme_should_propagate_errors(); 52 TRY_OR_FATAL_ERROR(m_playback_handler->on_enter()); 53} 54 55void PlaybackManager::resume_playback() 56{ 57 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Resuming playback."); 58 TRY_OR_FATAL_ERROR(m_playback_handler->play()); 59} 60 61void PlaybackManager::pause_playback() 62{ 63 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Pausing playback."); 64 if (!m_playback_handler->is_playing()) 65 warnln("Cannot pause."); 66 TRY_OR_FATAL_ERROR(m_playback_handler->pause()); 67} 68 69Time PlaybackManager::current_playback_time() 70{ 71 return m_playback_handler->current_time(); 72} 73 74Time PlaybackManager::duration() 75{ 76 auto duration_result = m_demuxer->duration(); 77 if (duration_result.is_error()) 78 dispatch_decoder_error(duration_result.release_error()); 79 return duration_result.release_value(); 80} 81 82void PlaybackManager::dispatch_fatal_error(Error error) 83{ 84 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Encountered fatal error: {}", error.string_literal()); 85 // FIXME: For threading, this will have to use a pre-allocated event to send to the main loop 86 // to be able to gracefully handle OOM. 87 VERIFY(&m_main_loop == &Core::EventLoop::current()); 88 FatalPlaybackErrorEvent event { move(error) }; 89 m_event_handler.dispatch_event(event); 90} 91 92void PlaybackManager::dispatch_decoder_error(DecoderError error) 93{ 94 switch (error.category()) { 95 case DecoderErrorCategory::EndOfStream: 96 dbgln_if(PLAYBACK_MANAGER_DEBUG, "{}", error.string_literal()); 97 TRY_OR_FATAL_ERROR(m_playback_handler->stop()); 98 break; 99 default: 100 dbgln("Playback error encountered: {}", error.string_literal()); 101 TRY_OR_FATAL_ERROR(m_playback_handler->stop()); 102 m_main_loop.post_event(m_event_handler, make<DecoderErrorEvent>(move(error))); 103 break; 104 } 105} 106 107void PlaybackManager::dispatch_new_frame(RefPtr<Gfx::Bitmap> frame) 108{ 109 m_main_loop.post_event(m_event_handler, make<VideoFramePresentEvent>(frame)); 110} 111 112bool PlaybackManager::dispatch_frame_queue_item(FrameQueueItem&& item) 113{ 114 if (item.is_error()) { 115 dispatch_decoder_error(item.release_error()); 116 return true; 117 } 118 119 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Sent frame for presentation"); 120 dispatch_new_frame(item.bitmap()); 121 return false; 122} 123 124void PlaybackManager::dispatch_state_change() 125{ 126 m_main_loop.post_event(m_event_handler, TRY_OR_FATAL_ERROR(try_make<PlaybackStateChangeEvent>())); 127} 128 129void PlaybackManager::timer_callback() 130{ 131 TRY_OR_FATAL_ERROR(m_playback_handler->on_timer_callback()); 132} 133 134void PlaybackManager::seek_to_timestamp(Time target_timestamp, SeekMode seek_mode) 135{ 136 TRY_OR_FATAL_ERROR(m_playback_handler->seek(target_timestamp, seek_mode)); 137} 138 139Optional<Time> PlaybackManager::seek_demuxer_to_most_recent_keyframe(Time timestamp, Optional<Time> earliest_available_sample) 140{ 141 // FIXME: When the demuxer is getting samples off the main thread in the future, this needs to 142 // mutex so that seeking can't happen while that thread is getting a sample. 143 auto result = m_demuxer->seek_to_most_recent_keyframe(m_selected_video_track, timestamp, move(earliest_available_sample)); 144 if (result.is_error()) 145 dispatch_decoder_error(result.release_error()); 146 return result.release_value(); 147} 148 149void PlaybackManager::restart_playback() 150{ 151 seek_to_timestamp(Time::zero()); 152} 153 154void PlaybackManager::start_timer(int milliseconds) 155{ 156 m_present_timer->start(milliseconds); 157} 158 159bool PlaybackManager::decode_and_queue_one_sample() 160{ 161 if (m_frame_queue->size() >= FRAME_BUFFER_COUNT) { 162 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Frame queue is full, stopping"); 163 return false; 164 } 165#if PLAYBACK_MANAGER_DEBUG 166 auto start_time = Time::now_monotonic(); 167#endif 168 169 auto enqueue_error = [&](DecoderError&& error, Time timestamp) { 170 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Enqueued decoder error: {}", error.string_literal()); 171 m_frame_queue->enqueue(FrameQueueItem::error_marker(move(error), timestamp)); 172 }; 173 174#define TRY_OR_ENQUEUE_ERROR(expression, timestamp) \ 175 ({ \ 176 auto&& _temporary_result = (expression); \ 177 if (_temporary_result.is_error()) { \ 178 enqueue_error(_temporary_result.release_error(), (timestamp)); \ 179 return false; \ 180 } \ 181 static_assert(!::AK::Detail::IsLvalueReference<decltype(_temporary_result.release_value())>, \ 182 "Do not return a reference from a fallible expression"); \ 183 _temporary_result.release_value(); \ 184 }) 185 186 auto frame_sample = TRY_OR_ENQUEUE_ERROR(m_demuxer->get_next_video_sample_for_track(m_selected_video_track), Time::min()); 187 OwnPtr<VideoFrame> decoded_frame = nullptr; 188 while (!decoded_frame) { 189 TRY_OR_ENQUEUE_ERROR(m_decoder->receive_sample(frame_sample->data()), frame_sample->timestamp()); 190 191 while (true) { 192 auto frame_result = m_decoder->get_decoded_frame(); 193 194 if (frame_result.is_error()) { 195 if (frame_result.error().category() == DecoderErrorCategory::NeedsMoreInput) 196 break; 197 198 enqueue_error(frame_result.release_error(), frame_sample->timestamp()); 199 return false; 200 } 201 202 decoded_frame = frame_result.release_value(); 203 VERIFY(decoded_frame); 204 } 205 } 206 207 auto& cicp = decoded_frame->cicp(); 208 cicp.adopt_specified_values(frame_sample->container_cicp()); 209 cicp.default_code_points_if_unspecified({ ColorPrimaries::BT709, TransferCharacteristics::BT709, MatrixCoefficients::BT709, VideoFullRangeFlag::Studio }); 210 211 // BT.601, BT.709 and BT.2020 have a similar transfer function to sRGB, so other applications 212 // (Chromium, VLC) forgo transfer characteristics conversion. We will emulate that behavior by 213 // handling those as sRGB instead, which causes no transfer function change in the output, 214 // unless display color management is later implemented. 215 switch (cicp.transfer_characteristics()) { 216 case TransferCharacteristics::BT601: 217 case TransferCharacteristics::BT709: 218 case TransferCharacteristics::BT2020BitDepth10: 219 case TransferCharacteristics::BT2020BitDepth12: 220 cicp.set_transfer_characteristics(TransferCharacteristics::SRGB); 221 break; 222 default: 223 break; 224 } 225 226 auto bitmap = TRY_OR_ENQUEUE_ERROR(decoded_frame->to_bitmap(), frame_sample->timestamp()); 227 m_frame_queue->enqueue(FrameQueueItem::frame(bitmap, frame_sample->timestamp())); 228 229#if PLAYBACK_MANAGER_DEBUG 230 auto end_time = Time::now_monotonic(); 231 dbgln("Decoding sample at {}ms took {}ms, queue contains {} items", frame_sample->timestamp().to_milliseconds(), (end_time - start_time).to_milliseconds(), m_frame_queue->size()); 232#endif 233 234 return true; 235} 236 237void PlaybackManager::on_decode_timer() 238{ 239 if (!decode_and_queue_one_sample()) { 240 // Note: When threading is implemented, this must be dispatched via an event loop. 241 TRY_OR_FATAL_ERROR(m_playback_handler->on_buffer_filled()); 242 return; 243 } 244 245 // Continually decode until buffering is complete 246 m_decode_timer->start(0); 247} 248 249Time PlaybackManager::PlaybackStateHandler::current_time() const 250{ 251 return m_manager.m_last_present_in_media_time; 252} 253 254ErrorOr<void> PlaybackManager::PlaybackStateHandler::seek(Time target_timestamp, SeekMode seek_mode) 255{ 256 return replace_handler_and_delete_this<SeekingStateHandler>(is_playing(), target_timestamp, seek_mode); 257} 258 259ErrorOr<void> PlaybackManager::PlaybackStateHandler::stop() 260{ 261 return replace_handler_and_delete_this<StoppedStateHandler>(); 262} 263 264template<class T, class... Args> 265ErrorOr<void> PlaybackManager::PlaybackStateHandler::replace_handler_and_delete_this(Args... args) 266{ 267 auto temp_handler = TRY(adopt_nonnull_own_or_enomem<PlaybackStateHandler>(new (nothrow) T(m_manager, args...))); 268 m_manager.m_playback_handler.swap(temp_handler); 269#if PLAYBACK_MANAGER_DEBUG 270 m_has_exited = true; 271 dbgln("Changing state from {} to {}", temp_handler->name(), m_manager.m_playback_handler->name()); 272#endif 273 m_manager.dispatch_state_change(); 274 TRY(m_manager.m_playback_handler->on_enter()); 275 return {}; 276} 277 278PlaybackManager& PlaybackManager::PlaybackStateHandler::manager() const 279{ 280#if PLAYBACK_MANAGER_DEBUG 281 VERIFY(!m_has_exited); 282#endif 283 return m_manager; 284} 285 286class PlaybackManager::ResumingStateHandler : public PlaybackManager::PlaybackStateHandler { 287public: 288 ResumingStateHandler(PlaybackManager& manager, bool playing) 289 : PlaybackStateHandler(manager) 290 , m_playing(playing) 291 { 292 } 293 ~ResumingStateHandler() override = default; 294 295protected: 296 ErrorOr<void> assume_next_state() 297 { 298 if (!m_playing) 299 return replace_handler_and_delete_this<PausedStateHandler>(); 300 return replace_handler_and_delete_this<PlayingStateHandler>(); 301 } 302 303 ErrorOr<void> play() override 304 { 305 m_playing = true; 306 manager().dispatch_state_change(); 307 return {}; 308 } 309 bool is_playing() override { return m_playing; } 310 ErrorOr<void> pause() override 311 { 312 m_playing = false; 313 manager().dispatch_state_change(); 314 return {}; 315 } 316 317 bool m_playing; 318}; 319 320class PlaybackManager::StartingStateHandler : public PlaybackManager::ResumingStateHandler { 321 using PlaybackManager::ResumingStateHandler::ResumingStateHandler; 322 323 ErrorOr<void> on_enter() override 324 { 325 return on_timer_callback(); 326 } 327 328 StringView name() override { return "Starting"sv; } 329 330 ErrorOr<void> on_timer_callback() override 331 { 332 // Once we're threaded, instead of checking for the count here we can just mutex 333 // in the queue until we display the first and then again for the second to store it. 334 if (manager().m_frame_queue->size() < 3) { 335 manager().m_decode_timer->start(0); 336 manager().start_timer(0); 337 return {}; 338 } 339 340 auto frame_to_display = manager().m_frame_queue->dequeue(); 341 manager().m_last_present_in_media_time = frame_to_display.timestamp(); 342 if (manager().dispatch_frame_queue_item(move(frame_to_display))) 343 return {}; 344 345 manager().m_next_frame.emplace(manager().m_frame_queue->dequeue()); 346 manager().m_decode_timer->start(0); 347 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Displayed frame at {}ms, emplaced second frame at {}ms, finishing start now", manager().m_last_present_in_media_time.to_milliseconds(), manager().m_next_frame->timestamp().to_milliseconds()); 348 if (!m_playing) 349 return replace_handler_and_delete_this<PausedStateHandler>(); 350 return replace_handler_and_delete_this<PlayingStateHandler>(); 351 } 352 353 ErrorOr<void> play() override 354 { 355 m_playing = true; 356 return {}; 357 } 358 bool is_playing() override { return m_playing; }; 359 ErrorOr<void> pause() override 360 { 361 m_playing = false; 362 return {}; 363 } 364 365 bool m_playing; 366}; 367 368class PlaybackManager::PlayingStateHandler : public PlaybackManager::PlaybackStateHandler { 369public: 370 PlayingStateHandler(PlaybackManager& manager) 371 : PlaybackStateHandler(manager) 372 { 373 } 374 ~PlayingStateHandler() override = default; 375 376private: 377 ErrorOr<void> on_enter() override 378 { 379 m_last_present_in_real_time = Time::now_monotonic(); 380 return on_timer_callback(); 381 } 382 383 StringView name() override { return "Playing"sv; } 384 385 bool is_playing() override { return true; }; 386 ErrorOr<void> pause() override 387 { 388 manager().m_last_present_in_media_time = current_time(); 389 return replace_handler_and_delete_this<PausedStateHandler>(); 390 } 391 ErrorOr<void> buffer() override 392 { 393 manager().m_last_present_in_media_time = current_time(); 394 return replace_handler_and_delete_this<BufferingStateHandler>(true); 395 } 396 397 Time current_time() const override 398 { 399 return manager().m_last_present_in_media_time + (Time::now_monotonic() - m_last_present_in_real_time); 400 } 401 402 ErrorOr<void> on_timer_callback() override 403 { 404 auto set_presentation_timer = [&]() { 405 auto frame_time_ms = (manager().m_next_frame->timestamp() - current_time()).to_milliseconds(); 406 VERIFY(frame_time_ms <= NumericLimits<int>::max()); 407 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Time until next frame is {}ms", frame_time_ms); 408 manager().start_timer(max(static_cast<int>(frame_time_ms), 0)); 409 }; 410 411 if (manager().m_next_frame.has_value() && current_time() < manager().m_next_frame->timestamp()) { 412 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Current time {}ms is too early to present the next frame at {}ms, delaying", current_time().to_milliseconds(), manager().m_next_frame->timestamp().to_milliseconds()); 413 set_presentation_timer(); 414 return {}; 415 } 416 417 Optional<FrameQueueItem> future_frame_item; 418 bool should_present_frame = false; 419 420 // Skip frames until we find a frame past the current playback time, and keep the one that precedes it to display. 421 while (!manager().m_frame_queue->is_empty()) { 422 future_frame_item.emplace(manager().m_frame_queue->dequeue()); 423 manager().m_decode_timer->start(0); 424 425 if (future_frame_item->timestamp() >= current_time() || future_frame_item->timestamp() == FrameQueueItem::no_timestamp) { 426 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Should present frame, future {} is error or after {}ms", future_frame_item->debug_string(), current_time().to_milliseconds()); 427 should_present_frame = true; 428 break; 429 } 430 431 if (manager().m_next_frame.has_value()) { 432 dbgln_if(PLAYBACK_MANAGER_DEBUG, "At {}ms: Dropped {} in favor of {}", current_time().to_milliseconds(), manager().m_next_frame->debug_string(), future_frame_item->debug_string()); 433 manager().m_skipped_frames++; 434 } 435 manager().m_next_frame.emplace(future_frame_item.release_value()); 436 } 437 438 // If we don't have both of these items, we can't present, since we need to set a timer for 439 // the next frame. Check if we need to buffer based on the current state. 440 if (!manager().m_next_frame.has_value() || !future_frame_item.has_value()) { 441#if PLAYBACK_MANAGER_DEBUG 442 StringBuilder debug_string_builder; 443 debug_string_builder.append("We don't have "sv); 444 if (!manager().m_next_frame.has_value()) { 445 debug_string_builder.append("a frame to present"sv); 446 if (!future_frame_item.has_value()) 447 debug_string_builder.append(" or a future frame"sv); 448 } else { 449 debug_string_builder.append("a future frame"sv); 450 } 451 debug_string_builder.append(", checking for error and buffering"sv); 452 dbgln_if(PLAYBACK_MANAGER_DEBUG, debug_string_builder.to_deprecated_string()); 453#endif 454 if (future_frame_item.has_value()) { 455 if (future_frame_item->is_error()) { 456 manager().dispatch_decoder_error(future_frame_item.release_value().release_error()); 457 return {}; 458 } 459 manager().m_next_frame.emplace(future_frame_item.release_value()); 460 } 461 TRY(buffer()); 462 return {}; 463 } 464 465 // If we have a frame, send it for presentation. 466 if (should_present_frame) { 467 auto now = Time::now_monotonic(); 468 manager().m_last_present_in_media_time += now - m_last_present_in_real_time; 469 m_last_present_in_real_time = now; 470 471 if (manager().dispatch_frame_queue_item(manager().m_next_frame.release_value())) 472 return {}; 473 } 474 475 // Now that we've presented the current frame, we can throw whatever error is next in queue. 476 // This way, we always display a frame before the stream ends, and should also show any frames 477 // we already had when a real error occurs. 478 if (future_frame_item->is_error()) { 479 manager().dispatch_decoder_error(future_frame_item.release_value().release_error()); 480 return {}; 481 } 482 483 // The future frame item becomes the next one to present. 484 manager().m_next_frame.emplace(future_frame_item.release_value()); 485 set_presentation_timer(); 486 return {}; 487 } 488 489 Time m_last_present_in_real_time = Time::zero(); 490}; 491 492class PlaybackManager::PausedStateHandler : public PlaybackManager::PlaybackStateHandler { 493public: 494 PausedStateHandler(PlaybackManager& manager) 495 : PlaybackStateHandler(manager) 496 { 497 } 498 ~PausedStateHandler() override = default; 499 500private: 501 StringView name() override { return "Paused"sv; } 502 503 ErrorOr<void> play() override 504 { 505 return replace_handler_and_delete_this<PlayingStateHandler>(); 506 } 507 bool is_playing() override { return false; }; 508}; 509 510class PlaybackManager::BufferingStateHandler : public PlaybackManager::ResumingStateHandler { 511 using PlaybackManager::ResumingStateHandler::ResumingStateHandler; 512 513 ErrorOr<void> on_enter() override 514 { 515 manager().m_decode_timer->start(0); 516 return {}; 517 } 518 519 StringView name() override { return "Buffering"sv; } 520 521 ErrorOr<void> on_buffer_filled() override 522 { 523 return assume_next_state(); 524 } 525}; 526 527class PlaybackManager::SeekingStateHandler : public PlaybackManager::ResumingStateHandler { 528public: 529 SeekingStateHandler(PlaybackManager& manager, bool playing, Time target_timestamp, SeekMode seek_mode) 530 : ResumingStateHandler(manager, playing) 531 , m_target_timestamp(target_timestamp) 532 , m_seek_mode(seek_mode) 533 { 534 } 535 ~SeekingStateHandler() override = default; 536 537private: 538 ErrorOr<void> on_enter() override 539 { 540 auto earliest_available_sample = manager().m_last_present_in_media_time; 541 if (manager().m_next_frame.has_value() && manager().m_next_frame->timestamp() != FrameQueueItem::no_timestamp) { 542 earliest_available_sample = min(earliest_available_sample, manager().m_next_frame->timestamp()); 543 } 544 auto keyframe_timestamp = manager().seek_demuxer_to_most_recent_keyframe(m_target_timestamp, earliest_available_sample); 545 546#if PLAYBACK_MANAGER_DEBUG 547 auto seek_mode_name = m_seek_mode == SeekMode::Accurate ? "Accurate"sv : "Fast"sv; 548 if (keyframe_timestamp.has_value()) { 549 dbgln("{} seeking to timestamp target {}ms, selected keyframe at {}ms", seek_mode_name, m_target_timestamp.to_milliseconds(), keyframe_timestamp->to_milliseconds()); 550 } else { 551 dbgln("{} seeking to timestamp target {}ms, demuxer kept its iterator position", seek_mode_name, m_target_timestamp.to_milliseconds()); 552 } 553#endif 554 555 if (m_seek_mode == SeekMode::Fast) { 556 m_target_timestamp = keyframe_timestamp.value_or(earliest_available_sample); 557 } 558 559 if (keyframe_timestamp.has_value()) { 560 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Timestamp is earlier than current media time, clearing queue"); 561 manager().m_frame_queue->clear(); 562 manager().m_next_frame.clear(); 563 } else if (m_target_timestamp >= manager().m_last_present_in_media_time && manager().m_next_frame.has_value() && manager().m_next_frame.value().timestamp() > m_target_timestamp) { 564 manager().m_last_present_in_media_time = m_target_timestamp; 565 return assume_next_state(); 566 } 567 568 return skip_samples_until_timestamp(); 569 } 570 571 ErrorOr<void> skip_samples_until_timestamp() 572 { 573 while (!manager().m_frame_queue->is_empty()) { 574 auto item = manager().m_frame_queue->dequeue(); 575 manager().m_decode_timer->start(0); 576 577 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Dequeuing frame at {}ms and comparing to seek target {}ms", item.timestamp().to_milliseconds(), m_target_timestamp.to_milliseconds()); 578 if (item.timestamp() > m_target_timestamp || item.timestamp() == FrameQueueItem::no_timestamp) { 579 // Fast seeking will result in an equal timestamp, so we can exit as soon as we see the next frame. 580 if (manager().m_next_frame.has_value()) { 581 manager().m_last_present_in_media_time = m_target_timestamp; 582 583 if (manager().dispatch_frame_queue_item(manager().m_next_frame.release_value())) 584 return {}; 585 } 586 587 manager().m_next_frame.emplace(item); 588 589 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Exiting seek to {} state at {}ms", m_playing ? "Playing" : "Paused", manager().m_last_present_in_media_time.to_milliseconds()); 590 return assume_next_state(); 591 } 592 manager().m_next_frame.emplace(item); 593 } 594 595 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Frame queue is empty while seeking, waiting for buffer fill."); 596 manager().m_decode_timer->start(0); 597 return {}; 598 } 599 600 StringView name() override { return "Seeking"sv; } 601 602 ErrorOr<void> seek(Time target_timestamp, SeekMode seek_mode) override 603 { 604 m_target_timestamp = target_timestamp; 605 m_seek_mode = seek_mode; 606 return on_enter(); 607 } 608 609 Time current_time() const override 610 { 611 return m_target_timestamp; 612 } 613 614 // We won't need this override when threaded, the queue can pause us in on_enter(). 615 ErrorOr<void> on_buffer_filled() override 616 { 617 dbgln_if(PLAYBACK_MANAGER_DEBUG, "Buffer filled while seeking, dequeuing until timestamp."); 618 return skip_samples_until_timestamp(); 619 } 620 621 bool m_playing { false }; 622 Time m_target_timestamp { Time::zero() }; 623 SeekMode m_seek_mode { SeekMode::Accurate }; 624}; 625 626class PlaybackManager::StoppedStateHandler : public PlaybackManager::PlaybackStateHandler { 627public: 628 StoppedStateHandler(PlaybackManager& manager) 629 : PlaybackStateHandler(manager) 630 { 631 } 632 ~StoppedStateHandler() override = default; 633 634private: 635 ErrorOr<void> on_enter() override 636 { 637 return {}; 638 } 639 640 StringView name() override { return "Stopped"sv; } 641 642 ErrorOr<void> play() override 643 { 644 manager().m_next_frame.clear(); 645 manager().m_frame_queue->clear(); 646 auto start_timestamp = manager().seek_demuxer_to_most_recent_keyframe(Time::zero()); 647 VERIFY(start_timestamp.has_value()); 648 manager().m_last_present_in_media_time = start_timestamp.release_value(); 649 return replace_handler_and_delete_this<StartingStateHandler>(true); 650 } 651 bool is_playing() override { return false; }; 652}; 653 654}