diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index 117c21ab71..5a900ce181 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -11,6 +11,8 @@ LOG_CHANNEL(cellAudio); +extern atomic_t g_recording_mode; + extern void lv2_sleep(u64 timeout, ppu_thread* ppu = nullptr); vm::gvar g_audio_buffer; @@ -290,8 +292,9 @@ void audio_ringbuffer::commit_data(f32* buf, u32 sample_cnt) m_dump.WriteData(buf, sample_cnt_in * static_cast(AudioSampleSize::FLOAT)); // Record audio if enabled - if (utils::video_provider& provider = g_fxo->get(); provider.can_consume_sample()) + if (g_recording_mode != recording_mode::stopped) { + utils::video_provider& provider = g_fxo->get(); provider.present_samples(reinterpret_cast(buf), sample_cnt, static_cast(cfg.audio_channels)); } diff --git a/rpcs3/Emu/Cell/Modules/cellRec.cpp b/rpcs3/Emu/Cell/Modules/cellRec.cpp index c793fbca88..b0de9c2365 100644 --- a/rpcs3/Emu/Cell/Modules/cellRec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRec.cpp @@ -176,7 +176,8 @@ public: { cellRec.notice("Stopping video sink. flush=%d", flush); - std::lock_guard lock(m_mtx); + std::lock_guard lock_video(m_video_mtx); + std::lock_guard lock_audio(m_audio_mtx); m_flush = flush; m_paused = false; m_frames_to_encode.clear(); @@ -188,7 +189,8 @@ public: { cellRec.notice("Pausing video sink. flush=%d", flush); - std::lock_guard lock(m_mtx); + std::lock_guard lock_video(m_video_mtx); + std::lock_guard lock_audio(m_audio_mtx); m_flush = flush; m_paused = true; } @@ -197,14 +199,15 @@ public: { cellRec.notice("Resuming video sink"); - std::lock_guard lock(m_mtx); + std::lock_guard lock_video(m_video_mtx); + std::lock_guard lock_audio(m_audio_mtx); m_flush = false; m_paused = false; } encoder_frame get_frame() { - std::lock_guard lock(m_mtx); + std::lock_guard lock_video(m_video_mtx); if (!m_frames_to_encode.empty()) { @@ -218,7 +221,7 @@ public: encoder_sample get_sample() { - std::lock_guard lock(m_mtx); + std::lock_guard lock(m_audio_mtx); if (!m_samples_to_encode.empty()) { diff --git a/rpcs3/util/media_utils.cpp b/rpcs3/util/media_utils.cpp index 9e21298dab..94a922acbe 100644 --- a/rpcs3/util/media_utils.cpp +++ b/rpcs3/util/media_utils.cpp @@ -781,7 +781,8 @@ namespace utils m_thread.reset(); } - std::lock_guard lock(m_mtx); + std::lock_guard lock_video(m_video_mtx); + std::lock_guard lock_audio(m_audio_mtx); m_frames_to_encode.clear(); m_samples_to_encode.clear(); has_error = false; @@ -1288,17 +1289,17 @@ namespace utils encoder_frame frame_data; bool got_frame = false; { - m_mtx.lock(); + m_video_mtx.lock(); if (m_frames_to_encode.empty()) { - m_mtx.unlock(); + m_video_mtx.unlock(); } else { frame_data = std::move(m_frames_to_encode.front()); m_frames_to_encode.pop_front(); - m_mtx.unlock(); + m_video_mtx.unlock(); got_frame = true; diff --git a/rpcs3/util/video_provider.cpp b/rpcs3/util/video_provider.cpp index a5888dadde..44669307a0 100644 --- a/rpcs3/util/video_provider.cpp +++ b/rpcs3/util/video_provider.cpp @@ -45,7 +45,8 @@ namespace utils return false; } - std::lock_guard lock(m_mutex); + std::lock_guard lock_video(m_video_mutex); + std::lock_guard lock_audio(m_audio_mutex); if (m_video_sink) { @@ -65,10 +66,13 @@ namespace utils m_type = sink ? type : recording_mode::stopped; m_video_sink = sink; + m_active = (m_type != recording_mode::stopped); - if (m_type == recording_mode::stopped) + if (!m_active) { - m_active = false; + m_last_video_pts_incoming = -1; + m_last_audio_pts_incoming = -1; + m_start_time_us.store(umax); } return true; @@ -76,7 +80,9 @@ namespace utils void video_provider::set_pause_time_us(usz pause_time_us) { - std::lock_guard lock(m_mutex); + std::lock_guard lock_video(m_video_mutex); + std::lock_guard lock_audio(m_audio_mutex); + m_pause_time_us = pause_time_us; } @@ -91,20 +97,6 @@ namespace utils if (g_recording_mode == recording_mode::stopped) { m_active = false; - return g_recording_mode; - } - - if (!m_active.exchange(true)) - { - m_current_encoder_frame = 0; - m_current_encoder_sample = 0; - m_last_video_pts_incoming = -1; - m_last_audio_pts_incoming = -1; - } - - if (m_current_encoder_frame == 0 && m_current_encoder_sample == 0) - { - m_encoder_start = steady_clock::now(); } return g_recording_mode; @@ -112,12 +104,19 @@ namespace utils bool video_provider::can_consume_frame() { - std::lock_guard lock(m_mutex); + if (!m_active) + { + return false; + } + + std::lock_guard lock_video(m_video_mutex); if (!m_video_sink || !m_video_sink->use_internal_video) + { return false; + } - const usz elapsed_us = std::chrono::duration_cast(steady_clock::now() - m_encoder_start).count(); + const usz elapsed_us = get_system_time() - m_start_time_us; ensure(elapsed_us >= m_pause_time_us); const usz timestamp_ms = (elapsed_us - m_pause_time_us) / 1000; @@ -127,15 +126,27 @@ namespace utils void video_provider::present_frame(std::vector& data, u32 pitch, u32 width, u32 height, bool is_bgra) { - std::lock_guard lock(m_mutex); + if (!m_active) + { + return; + } + + std::lock_guard lock_video(m_video_mutex); if (check_mode() == recording_mode::stopped) { return; } + const u64 current_time_us = get_system_time(); + + if (m_start_time_us.compare_and_swap_test(umax, current_time_us)) + { + media_log.notice("video_provider: start time = %d", current_time_us); + } + // Calculate presentation timestamp. - const usz elapsed_us = std::chrono::duration_cast(steady_clock::now() - m_encoder_start).count(); + const usz elapsed_us = current_time_us - m_start_time_us; ensure(elapsed_us >= m_pause_time_us); const usz timestamp_ms = (elapsed_us - m_pause_time_us) / 1000; @@ -150,41 +161,37 @@ namespace utils if (m_video_sink->add_frame(data, pitch, width, height, is_bgra ? AVPixelFormat::AV_PIX_FMT_BGRA : AVPixelFormat::AV_PIX_FMT_RGBA, timestamp_ms)) { m_last_video_pts_incoming = pts; - m_current_encoder_frame++; } } - bool video_provider::can_consume_sample() - { - std::lock_guard lock(m_mutex); - - if (!m_video_sink || !m_video_sink->use_internal_audio) - return false; - - const usz elapsed_us = std::chrono::duration_cast(steady_clock::now() - m_encoder_start).count(); - ensure(elapsed_us >= m_pause_time_us); - - const usz timestamp_us = elapsed_us - m_pause_time_us; - const s64 pts = m_video_sink->get_audio_pts(timestamp_us); - return pts > m_last_audio_pts_incoming; - } - void video_provider::present_samples(u8* buf, u32 sample_count, u16 channels) { - if (!buf || !sample_count || !channels) + if (!buf || !sample_count || !channels || !m_active) { return; } - std::lock_guard lock(m_mutex); + std::lock_guard lock_audio(m_audio_mutex); + + if (!m_video_sink || !m_video_sink->use_internal_audio) + { + return; + } if (check_mode() == recording_mode::stopped) { return; } + const u64 current_time_us = get_system_time(); + + if (m_start_time_us.compare_and_swap_test(umax, current_time_us)) + { + media_log.notice("video_provider: start time = %d", current_time_us); + } + // Calculate presentation timestamp. - const usz elapsed_us = std::chrono::duration_cast(steady_clock::now() - m_encoder_start).count(); + const usz elapsed_us = current_time_us - m_start_time_us; ensure(elapsed_us >= m_pause_time_us); const usz timestamp_us = elapsed_us - m_pause_time_us; @@ -199,7 +206,6 @@ namespace utils if (m_video_sink->add_audio_samples(buf, sample_count, channels, timestamp_us)) { m_last_audio_pts_incoming = pts; - m_current_encoder_sample += sample_count; } } } diff --git a/rpcs3/util/video_provider.h b/rpcs3/util/video_provider.h index 0e30b01f7e..0d2c29edfe 100644 --- a/rpcs3/util/video_provider.h +++ b/rpcs3/util/video_provider.h @@ -23,7 +23,6 @@ namespace utils bool can_consume_frame(); void present_frame(std::vector& data, u32 pitch, u32 width, u32 height, bool is_bgra); - bool can_consume_sample(); void present_samples(u8* buf, u32 sample_count, u16 channels); private: @@ -31,11 +30,10 @@ namespace utils recording_mode m_type = recording_mode::stopped; std::shared_ptr m_video_sink; - shared_mutex m_mutex{}; + shared_mutex m_video_mutex{}; + shared_mutex m_audio_mutex{}; atomic_t m_active{false}; - atomic_t m_current_encoder_frame{0}; - atomic_t m_current_encoder_sample{0}; - steady_clock::time_point m_encoder_start{}; + atomic_t m_start_time_us{umax}; s64 m_last_video_pts_incoming = -1; s64 m_last_audio_pts_incoming = -1; usz m_pause_time_us = 0; diff --git a/rpcs3/util/video_sink.h b/rpcs3/util/video_sink.h index 9f1aadd65e..caef9b1522 100644 --- a/rpcs3/util/video_sink.h +++ b/rpcs3/util/video_sink.h @@ -24,7 +24,7 @@ namespace utils if (m_flush || m_paused) return false; - std::lock_guard lock(m_mtx); + std::lock_guard lock(m_video_mtx); m_frames_to_encode.emplace_back(timestamp_ms, pitch, width, height, pixel_format, std::move(frame)); return true; } @@ -102,7 +102,7 @@ namespace utils bool use_internal_video = false; // True if we want to fetch frames from rsx protected: - shared_mutex m_mtx; + shared_mutex m_video_mtx; std::deque m_frames_to_encode; shared_mutex m_audio_mtx; std::deque m_samples_to_encode;