recording: optimize access to video recorder

Use separate locks for audio and video
Fix audio mutex usage in cellRec.
Removes can_consume_sample, since we don't do any processing
between can_consume_sample and present_samples.
Use get_system_time for consistency.
Move pts reset to set_video_sink.
Make start time atomic.
Remove frame and sample counts.
Use m_active to early out to reduce mutex locks.
Do not try to present samples if the recording mode is stopped anyway.
This commit is contained in:
Megamouse 2023-11-29 19:12:06 +01:00
parent 826cdbb507
commit 9e76e14a79
6 changed files with 70 additions and 59 deletions

View File

@ -11,6 +11,8 @@
LOG_CHANNEL(cellAudio);
extern atomic_t<recording_mode> g_recording_mode;
extern void lv2_sleep(u64 timeout, ppu_thread* ppu = nullptr);
vm::gvar<char, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT> 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<u32>(AudioSampleSize::FLOAT));
// Record audio if enabled
if (utils::video_provider& provider = g_fxo->get<utils::video_provider>(); provider.can_consume_sample())
if (g_recording_mode != recording_mode::stopped)
{
utils::video_provider& provider = g_fxo->get<utils::video_provider>();
provider.present_samples(reinterpret_cast<u8*>(buf), sample_cnt, static_cast<u32>(cfg.audio_channels));
}

View File

@ -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())
{

View File

@ -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;

View File

@ -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<std::chrono::microseconds>(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<u8>& 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<std::chrono::microseconds>(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<std::chrono::microseconds>(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<std::chrono::microseconds>(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;
}
}
}

View File

@ -23,7 +23,6 @@ namespace utils
bool can_consume_frame();
void present_frame(std::vector<u8>& 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<video_sink> m_video_sink;
shared_mutex m_mutex{};
shared_mutex m_video_mutex{};
shared_mutex m_audio_mutex{};
atomic_t<bool> m_active{false};
atomic_t<usz> m_current_encoder_frame{0};
atomic_t<usz> m_current_encoder_sample{0};
steady_clock::time_point m_encoder_start{};
atomic_t<usz> 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;

View File

@ -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<encoder_frame> m_frames_to_encode;
shared_mutex m_audio_mtx;
std::deque<encoder_sample> m_samples_to_encode;