18 #include <condition_variable>
28 #include <libavdevice/avdevice.h>
29 #include <libavutil/imgutils.h>
36 #include <audioclient.h>
37 #include <mmdeviceapi.h>
46 #if defined(__linux__)
51 : settings(new_settings) {}
57 if (format_context)
return;
58 avdevice_register_all();
59 AVInputFormat* input_format =
const_cast<AVInputFormat*
>(av_find_input_format(
"pulse"));
61 throw InvalidOptions(
"FFmpeg PulseAudio input is unavailable for system audio capture.");
64 format_context = avformat_alloc_context();
65 if (!format_context) {
66 throw OutOfMemory(
"Unable to allocate system audio capture context.");
68 format_context->interrupt_callback.callback = InterruptCallback;
69 format_context->interrupt_callback.opaque = &close_requested;
71 AVDictionary* options =
nullptr;
72 av_dict_set(&options,
"sample_rate", std::to_string(settings.audio_sample_rate).c_str(), 0);
73 av_dict_set(&options,
"channels", std::to_string(settings.audio_channels).c_str(), 0);
74 const std::string device = settings.audio_device.empty() ?
"@DEFAULT_MONITOR@" : settings.audio_device;
75 const int open_result = avformat_open_input(&format_context, device.c_str(), input_format, &options);
76 av_dict_free(&options);
77 if (open_result < 0) {
78 throw InvalidFile(
"Unable to open system audio capture input: " + std::string(
av_err2str(open_result)), device);
80 if (avformat_find_stream_info(format_context,
nullptr) < 0) {
81 throw InvalidFile(
"Unable to read system audio capture stream information.", device);
83 for (
unsigned int index = 0; index < format_context->nb_streams; ++index) {
84 if (format_context->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
85 audio_stream =
static_cast<int>(index);
89 if (audio_stream < 0) {
90 throw InvalidFile(
"No audio stream found in system audio capture input.", device);
92 AVStream* stream = format_context->streams[audio_stream];
93 const AVCodec*
codec = avcodec_find_decoder(stream->codecpar->codec_id);
94 codec_context =
codec ? ffmpeg_get_codec_context(stream,
codec) : nullptr;
95 if (!codec_context || avcodec_open2(codec_context,
codec,
nullptr) < 0) {
96 throw InvalidCodec(
"Unable to open system audio capture decoder.", device);
98 packet = av_packet_alloc();
99 decoded_frame = av_frame_alloc();
100 if (!packet || !decoded_frame) {
101 throw OutOfMemory(
"Unable to allocate system audio capture buffers.");
103 settings.audio_sample_rate = codec_context->sample_rate > 0
104 ? codec_context->sample_rate : settings.audio_sample_rate;
105 channels.assign(settings.audio_channels, {});
106 close_requested =
false;
107 worker = std::thread(&SystemAudioCapture::CaptureLoop,
this);
112 close_requested =
true;
114 if (worker.joinable()) {
117 if (decoded_frame) av_frame_free(&decoded_frame);
118 if (packet) av_packet_free(&packet);
119 if (codec_context) avcodec_free_context(&codec_context);
120 if (format_context) avformat_close_input(&format_context);
125 int sample_count = 0;
126 for (int64_t frame_number = last_output_frame + 1; frame_number <= number; ++frame_number) {
128 frame_number, fps, settings.audio_sample_rate, settings.audio_channels);
130 last_output_frame = std::max(last_output_frame, number);
131 if (!frame || sample_count <= 0)
return;
133 std::unique_lock<std::mutex> lock(queue_mutex);
139 const auto wait_time = timeline_started
140 ? std::chrono::milliseconds(100)
141 : std::chrono::milliseconds(3000);
142 ready.wait_for(lock, wait_time, [
this, sample_count]() {
143 return close_requested || (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count);
145 if (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count) {
146 timeline_started =
true;
148 frame->SampleRate(settings.audio_sample_rate);
150 for (
int channel = 0; channel < settings.audio_channels; ++channel) {
151 std::vector<float> samples(sample_count, 0.0f);
152 if (channel <
static_cast<int>(channels.size())) {
153 const int available = std::min(sample_count,
static_cast<int>(channels[channel].size()));
154 for (
int index = 0; index < available; ++index) {
155 samples[index] = channels[channel].front();
156 channels[channel].pop_front();
159 frame->AddAudio(
true, channel, 0, samples.data(), sample_count, 1.0f);
165 std::lock_guard<std::mutex> lock(queue_mutex);
166 for (
auto& channel : channels) channel.clear();
167 last_output_frame = 0;
168 timeline_started =
false;
171 int SampleRate()
const {
return settings.audio_sample_rate; }
172 int Channels()
const {
return settings.audio_channels; }
175 static int InterruptCallback(
void* opaque)
177 const auto* requested =
static_cast<std::atomic<bool>*
>(opaque);
178 return requested && requested->load() ? 1 : 0;
181 float SampleAt(
const AVFrame* frame,
int channel,
int sample)
const
183 const AVSampleFormat format =
static_cast<AVSampleFormat
>(frame->format);
184 const bool planar = av_sample_fmt_is_planar(format) != 0;
185 const int source_channels = std::max(1,
187 codec_context->ch_layout.nb_channels
189 codec_context->channels
192 const int source_channel = std::min(channel, source_channels - 1);
193 const uint8_t* data = planar ? frame->extended_data[source_channel] : frame->extended_data[0];
194 const int offset = planar ? sample : sample * source_channels + source_channel;
196 case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
197 return (
static_cast<const uint8_t*
>(
static_cast<const void*
>(data))[offset] - 128) / 128.0f;
198 case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
199 return static_cast<const int16_t*
>(
static_cast<const void*
>(data))[offset] / 32768.0f;
200 case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
201 return static_cast<float>(
static_cast<const int32_t*
>(
static_cast<const void*
>(data))[offset] / 2147483648.0);
202 case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
203 return static_cast<const float*
>(
static_cast<const void*
>(data))[offset];
204 case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
205 return static_cast<float>(
static_cast<const double*
>(
static_cast<const void*
>(data))[offset]);
213 while (!close_requested) {
214 const int read_result = av_read_frame(format_context, packet);
215 if (read_result == AVERROR(EAGAIN))
continue;
216 if (read_result < 0)
break;
217 if (packet->stream_index != audio_stream) {
218 av_packet_unref(packet);
221 const int send_result = avcodec_send_packet(codec_context, packet);
222 av_packet_unref(packet);
223 if (send_result < 0)
continue;
224 while (avcodec_receive_frame(codec_context, decoded_frame) == 0) {
225 std::lock_guard<std::mutex> lock(queue_mutex);
226 for (
int channel = 0; channel < settings.audio_channels; ++channel) {
227 const size_t max_samples =
static_cast<size_t>(settings.audio_sample_rate) * 10;
228 for (
int sample = 0; sample < decoded_frame->nb_samples; ++sample) {
229 if (channels[channel].size() >= max_samples) channels[channel].pop_front();
230 channels[channel].push_back(SampleAt(decoded_frame, channel, sample));
233 av_frame_unref(decoded_frame);
240 AVFormatContext* format_context =
nullptr;
241 AVCodecContext* codec_context =
nullptr;
242 AVPacket* packet =
nullptr;
243 AVFrame* decoded_frame =
nullptr;
244 int audio_stream = -1;
245 std::atomic<bool> close_requested {
false };
247 std::mutex queue_mutex;
248 std::condition_variable ready;
249 std::vector<std::deque<float>> channels;
250 int64_t last_output_frame = 0;
251 bool timeline_started =
false;
253 #elif defined(_WIN32)
258 : settings(new_settings) {}
264 if (worker.joinable())
return;
265 close_requested =
false;
266 worker = std::thread(&SystemAudioCapture::CaptureLoop,
this);
267 std::unique_lock<std::mutex> lock(state_mutex);
268 state_ready.wait_for(lock, std::chrono::seconds(5), [
this]() {
return opened || failed; });
270 close_requested =
true;
272 if (worker.joinable()) worker.join();
273 throw InvalidOptions(error.empty() ?
"Unable to open WASAPI system audio loopback capture." : error);
279 close_requested =
true;
281 if (worker.joinable()) worker.join();
287 int sample_count = 0;
288 for (int64_t frame_number = last_output_frame + 1; frame_number <= number; ++frame_number) {
291 last_output_frame = std::max(last_output_frame, number);
292 if (!frame || sample_count <= 0)
return;
293 std::unique_lock<std::mutex> lock(queue_mutex);
297 const auto wait_time = timeline_started
298 ? std::chrono::milliseconds(100)
299 : std::chrono::milliseconds(3000);
300 ready.wait_for(lock, wait_time, [
this, sample_count]() {
301 return close_requested || (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count);
303 if (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count) {
304 timeline_started =
true;
306 frame->SampleRate(sample_rate);
308 for (
int channel = 0; channel < channel_count; ++channel) {
309 std::vector<float> samples(sample_count, 0.0f);
310 const int available = std::min(sample_count,
static_cast<int>(channels[channel].size()));
311 for (
int index = 0; index < available; ++index) {
312 samples[index] = channels[channel].front();
313 channels[channel].pop_front();
315 frame->AddAudio(
true, channel, 0, samples.data(), sample_count, 1.0f);
321 std::lock_guard<std::mutex> lock(queue_mutex);
322 for (
auto& channel : channels) channel.clear();
323 last_output_frame = 0;
324 timeline_started =
false;
327 int SampleRate()
const {
return sample_rate; }
328 int Channels()
const {
return channel_count; }
331 template <
typename T>
static void Release(T*& value)
333 if (value) { value->Release(); value =
nullptr; }
336 void Fail(
const std::string& message)
338 std::lock_guard<std::mutex> lock(state_mutex);
341 state_ready.notify_all();
346 IMMDeviceEnumerator* enumerator =
nullptr;
347 IMMDevice* device =
nullptr;
348 IAudioClient* client =
nullptr;
349 IAudioCaptureClient* capture =
nullptr;
350 WAVEFORMATEX* format =
nullptr;
351 const HRESULT com_result = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
352 const bool uninitialize_com = SUCCEEDED(com_result);
353 HRESULT result = CoCreateInstance(CLSID_MMDeviceEnumerator,
nullptr, CLSCTX_ALL,
354 IID_IMMDeviceEnumerator,
reinterpret_cast<void**
>(&enumerator));
355 if (SUCCEEDED(result)) {
356 result = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
358 if (SUCCEEDED(result)) {
359 result = device->Activate(IID_IAudioClient, CLSCTX_ALL,
nullptr,
reinterpret_cast<void**
>(&client));
361 if (SUCCEEDED(result)) result = client->GetMixFormat(&format);
362 if (SUCCEEDED(result)) {
363 result = client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK,
364 0, 0, format,
nullptr);
366 if (SUCCEEDED(result)) {
367 result = client->GetService(IID_IAudioCaptureClient,
reinterpret_cast<void**
>(&capture));
369 if (SUCCEEDED(result)) result = client->Start();
370 if (FAILED(result) || !format || !capture) {
371 Fail(
"Unable to initialize WASAPI system audio loopback capture (HRESULT " + std::to_string(result) +
").");
372 if (format) CoTaskMemFree(format);
373 Release(capture); Release(client); Release(device); Release(enumerator);
374 if (uninitialize_com) CoUninitialize();
378 sample_rate =
static_cast<int>(format->nSamplesPerSec);
379 channel_count = std::max(1, std::min(2,
static_cast<int>(format->nChannels)));
380 channels.assign(channel_count, {});
381 bool floating_point = format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT;
382 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE && format->cbSize >= 22) {
383 const auto* extensible =
reinterpret_cast<const WAVEFORMATEXTENSIBLE*
>(format);
384 floating_point = extensible->SubFormat.Data1 == WAVE_FORMAT_IEEE_FLOAT;
387 std::lock_guard<std::mutex> lock(state_mutex);
389 state_ready.notify_all();
392 while (!close_requested) {
393 UINT32 packet_frames = 0;
394 if (FAILED(capture->GetNextPacketSize(&packet_frames)))
break;
395 if (packet_frames == 0) {
396 std::this_thread::sleep_for(std::chrono::milliseconds(2));
399 BYTE* data =
nullptr;
402 if (FAILED(capture->GetBuffer(&data, &frames, &flags,
nullptr,
nullptr)))
break;
404 std::lock_guard<std::mutex> lock(queue_mutex);
405 for (UINT32 frame_index = 0; frame_index < frames; ++frame_index) {
406 for (
int channel = 0; channel < channel_count; ++channel) {
408 if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT) && data) {
409 const int offset =
static_cast<int>(frame_index) * format->nChannels + channel;
410 if (floating_point && format->wBitsPerSample == 32) {
411 sample =
reinterpret_cast<const float*
>(data)[offset];
412 }
else if (format->wBitsPerSample == 16) {
413 sample =
reinterpret_cast<const int16_t*
>(data)[offset] / 32768.0f;
414 }
else if (format->wBitsPerSample == 32) {
415 sample =
static_cast<float>(
reinterpret_cast<const int32_t*
>(data)[offset] / 2147483648.0);
418 const size_t max_samples =
static_cast<size_t>(sample_rate) * 10;
419 if (channels[channel].size() >= max_samples) channels[channel].pop_front();
420 channels[channel].push_back(sample);
424 capture->ReleaseBuffer(frames);
429 CoTaskMemFree(format);
430 Release(capture); Release(client); Release(device); Release(enumerator);
431 if (uninitialize_com) CoUninitialize();
435 std::atomic<bool> close_requested {
false };
437 std::mutex queue_mutex;
438 std::condition_variable ready;
439 std::vector<std::deque<float>> channels;
440 int64_t last_output_frame = 0;
441 bool timeline_started =
false;
442 int sample_rate = 48000;
443 int channel_count = 2;
444 std::mutex state_mutex;
445 std::condition_variable state_ready;
466 std::string fraction_to_string(
const Fraction& value)
468 std::stringstream stream;
469 stream << value.
num <<
"/" << value.
den;
473 void set_option(AVDictionary** options,
const std::string& key,
const std::string& value)
475 av_dict_set(options, key.c_str(), value.c_str(), 0);
478 bool option_enabled(
const std::map<std::string, std::string>& options,
const std::string& key)
480 const auto option = options.find(key);
481 if (option == options.end()) {
484 return option->second ==
"1" || option->second ==
"true" || option->second ==
"yes";
487 int option_int(
const std::map<std::string, std::string>& options,
const std::string& key,
int fallback)
489 const auto option = options.find(key);
490 if (option == options.end()) {
494 return std::stoi(option->second);
500 int capture_interrupt_callback(
void* opaque)
502 const auto* reader =
static_cast<std::atomic<bool>*
>(opaque);
503 return reader && reader->load() ? 1 : 0;
506 std::string avfoundation_video_name(
const std::string& input_name)
508 const size_t separator = input_name.find(
':');
509 return separator == std::string::npos ? input_name : input_name.substr(0, separator);
512 std::string avfoundation_audio_name(
const std::string& input_name)
514 const size_t separator = input_name.find(
':');
515 return separator == std::string::npos ?
"none" : input_name.substr(separator + 1);
518 bool resolve_avfoundation_video_index(
519 AVInputFormat* input_format,
520 const std::string& video_name,
521 std::string& video_index)
523 const auto is_digit = [](
unsigned char value) {
524 return std::isdigit(value) != 0;
526 if (video_name.empty()
527 || video_name ==
"default"
528 || video_name ==
"none"
529 || std::all_of(video_name.begin(), video_name.end(), is_digit)) {
533 AVDeviceInfoList* device_list =
nullptr;
534 const int result = avdevice_list_input_sources(input_format,
nullptr,
nullptr, &device_list);
535 if (result < 0 || !device_list) {
536 avdevice_free_list_devices(&device_list);
541 for (
int index = 0; index < device_list->nb_devices; ++index) {
542 const AVDeviceInfo* device = device_list->devices[index];
543 if (!device || !device->device_name) {
546 const std::string name = device->device_name;
547 const std::string description = device->device_description
548 ? device->device_description
549 : device->device_name;
550 if (video_name == name || video_name == description) {
551 video_index = std::all_of(name.begin(), name.end(), is_digit)
553 : std::to_string(index);
558 avdevice_free_list_devices(&device_list);
563 #if defined(HAVE_WAYLAND_CAPTURE)
570 : settings(new_settings)
571 , backend_reader(nullptr)
576 , format_context(nullptr)
577 , codec_context(nullptr)
578 , source_frame(nullptr)
579 , rgba_frame(nullptr)
581 , sws_context(nullptr)
582 , close_requested(false)
583 , system_audio(nullptr)
590 #if defined(__linux__) || defined(_WIN32)
592 system_audio = std::make_unique<SystemAudioCapture>(settings);
595 if (UsesWaylandPortal()) {
596 #if defined(HAVE_WAYLAND_CAPTURE)
598 if (!backend_reader) {
599 throw InvalidOptions(
"Wayland screen capture backend is unavailable in this build.");
602 throw InvalidOptions(
"Wayland screen capture backend is unavailable in this build.");
614 return backend_reader ? backend_reader->IsOpen() : is_open;
619 #if defined(__linux__)
623 #if defined(HAVE_WAYLAND_CAPTURE)
629 #elif defined(_WIN32)
631 #elif defined(__APPLE__)
641 #if defined(__linux__)
645 avdevice_register_all();
647 && av_find_input_format(
"pulse") !=
nullptr;
648 #elif defined(_WIN32)
658 #if defined(__linux__)
659 const char* session = std::getenv(
"XDG_SESSION_TYPE");
663 if (!session || std::string(session) ==
"x11") {
666 #elif defined(_WIN32)
668 #elif defined(__APPLE__)
674 void ScreenCaptureReader::ValidateSettings()
const
677 throw InvalidOptions(
"Screen capture backend is not supported on this OS or session.");
679 if (!UsesFFmpegDevice() && !UsesWaylandPortal()) {
680 throw InvalidOptions(
"Screen capture backend is not implemented in this build.");
683 throw InvalidOptions(
"Screen capture requires a positive width and height.");
686 throw InvalidOptions(
"Screen capture requires a positive frame rate.");
689 throw InvalidOptions(
"System audio capture is not supported by this screen capture backend.");
692 throw InvalidSampleRate(
"System audio capture requires a sample rate of at least 8000 Hz.");
695 throw InvalidChannels(
"System audio capture requires one or two channels.");
699 bool ScreenCaptureReader::UsesFFmpegDevice()
const
704 || settings.
options.count(
"input_format_name");
707 bool ScreenCaptureReader::UsesWaylandPortal()
const
712 std::string ScreenCaptureReader::InputFormatName()
const
714 const auto override_format = settings.
options.find(
"input_format_name");
715 if (override_format != settings.
options.end()) {
716 return override_format->second;
725 return "avfoundation";
730 std::string ScreenCaptureReader::InputName()
const
732 if (InputFormatName() ==
"v4l2") {
733 return settings.
display.empty() ?
"/dev/video0" : settings.
display;
735 if (InputFormatName() ==
"dshow") {
738 if (InputFormatName() ==
"gdigrab") {
741 if (InputFormatName() ==
"avfoundation") {
742 return settings.
display.empty() ?
"Capture screen 0:none" : settings.
display;
745 std::string display = settings.
display;
746 if (display.empty()) {
747 const char* env_display = std::getenv(
"DISPLAY");
748 display = env_display ? env_display :
":0.0";
750 if (InputFormatName() ==
"x11grab" && settings.
options.count(
"window_id")) {
754 std::stringstream input;
755 input << display <<
"+" << settings.
x <<
"," << settings.
y;
759 void ScreenCaptureReader::PopulateInfo()
791 if (backend_reader) {
792 if (backend_reader->IsOpen())
return;
793 manual_system_audio =
false;
795 system_audio->Open();
801 backend_reader->Open();
803 if (system_audio) system_audio->Close();
811 manual_system_audio =
false;
813 system_audio->Open();
818 close_requested =
false;
823 if (system_audio) system_audio->Close();
829 void ScreenCaptureReader::OpenDevice()
831 avdevice_register_all();
833 AVInputFormat* input_format =
const_cast<AVInputFormat*
>(av_find_input_format(InputFormatName().c_str()));
834 std::string input_name = InputName();
836 throw InvalidOptions(
"FFmpeg input device is not available: " + InputFormatName(), input_name);
839 format_context = avformat_alloc_context();
840 if (!format_context) {
841 throw OutOfMemory(
"Unable to allocate capture format context.", input_name);
843 format_context->interrupt_callback.callback = capture_interrupt_callback;
844 format_context->interrupt_callback.opaque = &close_requested;
846 AVDictionary* options =
nullptr;
847 const bool use_device_defaults = settings.
options.count(
"use_device_defaults") > 0;
848 const bool post_capture_crop = option_enabled(settings.
options,
"crop_after_capture");
849 if (!use_device_defaults && !post_capture_crop) {
850 set_option(&options,
"framerate", fraction_to_string(settings.
fps));
851 set_option(&options,
"video_size", std::to_string(settings.
width) +
"x" + std::to_string(settings.
height));
852 }
else if (post_capture_crop) {
853 const int source_width = option_int(settings.
options,
"crop_source_width", settings.
width);
854 const int source_height = option_int(settings.
options,
"crop_source_height", settings.
height);
855 set_option(&options,
"framerate", fraction_to_string(settings.
fps));
856 set_option(&options,
"video_size", std::to_string(source_width) +
"x" + std::to_string(source_height));
858 if (InputFormatName() ==
"x11grab") {
859 set_option(&options,
"draw_mouse", settings.
include_cursor ?
"1" :
"0");
860 set_option(&options,
"show_region", settings.
show_region ?
"1" :
"0");
861 }
else if (InputFormatName() ==
"gdigrab") {
862 set_option(&options,
"draw_mouse", settings.
include_cursor ?
"1" :
"0");
863 set_option(&options,
"show_region", settings.
show_region ?
"1" :
"0");
864 set_option(&options,
"offset_x", std::to_string(settings.
x));
865 set_option(&options,
"offset_y", std::to_string(settings.
y));
866 }
else if (InputFormatName() ==
"avfoundation") {
867 set_option(&options,
"capture_cursor", settings.
include_cursor ?
"1" :
"0");
868 std::string video_index;
869 if (resolve_avfoundation_video_index(input_format, avfoundation_video_name(input_name), video_index)) {
870 set_option(&options,
"video_device_index", video_index);
871 input_name =
":" + avfoundation_audio_name(input_name);
874 for (
const auto& option : settings.
options) {
875 if (option.first ==
"input_format_name"
876 || option.first ==
"use_device_defaults"
877 || option.first ==
"crop_after_capture"
878 || option.first ==
"crop_source_width"
879 || option.first ==
"crop_source_height") {
882 set_option(&options, option.first, option.second);
885 const int result = avformat_open_input(&format_context, input_name.c_str(), input_format, &options);
886 av_dict_free(&options);
888 throw InvalidFile(
"Unable to open screen capture input: " + std::string(
av_err2str(result)), input_name);
892 void ScreenCaptureReader::OpenDecoder()
894 if (avformat_find_stream_info(format_context,
nullptr) < 0) {
895 throw InvalidFile(
"Unable to read capture stream information.", InputName());
898 for (
unsigned int index = 0; index < format_context->nb_streams; ++index) {
899 if (format_context->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
900 video_stream =
static_cast<int>(index);
904 if (video_stream < 0) {
905 throw InvalidFile(
"No video stream found in capture input.", InputName());
908 AVStream* stream = format_context->streams[video_stream];
909 const AVCodec*
codec = avcodec_find_decoder(stream->codecpar->codec_id);
911 throw InvalidCodec(
"No decoder available for capture stream.", InputName());
914 codec_context = ffmpeg_get_codec_context(stream,
codec);
915 if (!codec_context || avcodec_open2(codec_context,
codec,
nullptr) < 0) {
916 throw InvalidCodec(
"Unable to open capture stream decoder.", InputName());
919 info.
width = codec_context->width > 0 ? codec_context->width : settings.
width;
920 info.
height = codec_context->height > 0 ? codec_context->height : settings.
height;
921 if (option_enabled(settings.
options,
"crop_after_capture")) {
929 if (codec_context->framerate.num > 0 && codec_context->framerate.den > 0) {
930 info.
fps =
Fraction(codec_context->framerate.num, codec_context->framerate.den);
932 }
else if (stream->avg_frame_rate.num > 0 && stream->avg_frame_rate.den > 0) {
933 info.
fps =
Fraction(stream->avg_frame_rate.num, stream->avg_frame_rate.den);
935 }
else if (stream->r_frame_rate.num > 0 && stream->r_frame_rate.den > 0) {
936 info.
fps =
Fraction(stream->r_frame_rate.num, stream->r_frame_rate.den);
940 source_frame = av_frame_alloc();
941 rgba_frame = av_frame_alloc();
942 packet = av_packet_alloc();
943 if (!source_frame || !rgba_frame || !packet) {
944 throw OutOfMemory(
"Unable to allocate capture decoder frames.", InputName());
950 if (backend_reader) {
951 if (!backend_reader->IsOpen()) {
952 throw ReaderClosed(
"The ScreenCaptureReader is closed. Call Open() before GetFrame().");
954 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
955 auto frame = backend_reader->GetFrame(number);
956 if (system_audio && !manual_system_audio) system_audio->AddFrameAudio(frame, number,
info.
fps);
960 throw ReaderClosed(
"The ScreenCaptureReader is closed. Call Open() before GetFrame().");
963 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
964 auto frame = DecodeNextFrame(number);
965 if (system_audio && !manual_system_audio) system_audio->AddFrameAudio(frame, number,
info.
fps);
972 system_audio->AddFrameAudio(frame, output_frame_number,
info.
fps);
978 manual_system_audio =
true;
980 system_audio->Reset();
984 std::shared_ptr<Frame> ScreenCaptureReader::DecodeNextFrame(int64_t number)
986 while (!close_requested) {
987 const int read_result = av_read_frame(format_context, packet);
988 if (read_result == AVERROR(EAGAIN)) {
989 std::this_thread::sleep_for(std::chrono::milliseconds(5));
992 if (read_result < 0) {
993 const std::string message = frames_read > 0
994 ?
"Capture input ended after " + std::to_string(frames_read) +
" frame(s): "
995 :
"Capture input ended before a frame could be read: ";
999 if (packet->stream_index != video_stream) {
1000 av_packet_unref(packet);
1005 const int64_t packet_timestamp = packet->pts != AV_NOPTS_VALUE ? packet->pts : packet->dts;
1006 const int send_result = avcodec_send_packet(codec_context, packet);
1007 av_packet_unref(packet);
1008 if (send_result < 0) {
1012 const int receive_result = avcodec_receive_frame(codec_context, source_frame);
1013 if (receive_result == AVERROR(EAGAIN)) {
1016 if (receive_result < 0) {
1017 throw InvalidFile(
"Unable to decode capture frame: " + std::string(
av_err2str(receive_result)), InputName());
1020 const AVStream* stream = format_context->streams[video_stream];
1021 int64_t frame_timestamp = source_frame->best_effort_timestamp;
1022 if (frame_timestamp == AV_NOPTS_VALUE) {
1023 frame_timestamp = source_frame->pts;
1025 if (frame_timestamp == AV_NOPTS_VALUE) {
1026 frame_timestamp = packet_timestamp;
1028 double capture_timestamp = std::numeric_limits<double>::quiet_NaN();
1029 if (frame_timestamp != AV_NOPTS_VALUE && stream) {
1030 capture_timestamp =
static_cast<double>(frame_timestamp) * av_q2d(stream->time_base);
1033 const int width = source_frame->width > 0 ? source_frame->width :
info.
width;
1034 const int height = source_frame->height > 0 ? source_frame->height :
info.
height;
1037 sws_context = sws_getCachedContext(
1050 throw InvalidFile(
"Unable to create capture pixel conversion context.", InputName());
1053 const int bytes_per_pixel = 4;
1054 const size_t buffer_size =
static_cast<size_t>(width) * height * bytes_per_pixel;
1055 unsigned char* buffer =
static_cast<unsigned char*
>(aligned_malloc(buffer_size));
1057 throw OutOfMemory(
"Unable to allocate capture frame buffer.", InputName());
1060 av_image_fill_arrays(rgba_frame->data, rgba_frame->linesize, buffer, AV_PIX_FMT_RGBA, width, height, 1);
1061 const int scaled_lines = sws_scale(sws_context, source_frame->data, source_frame->linesize, 0, height, rgba_frame->data, rgba_frame->linesize);
1062 av_frame_unref(source_frame);
1064 if (scaled_lines <= 0) {
1069 int output_width = width;
1070 int output_height = height;
1071 unsigned char* output_buffer = buffer;
1072 if (option_enabled(settings.
options,
"crop_after_capture")) {
1073 const int crop_x = std::max(0, std::min(settings.
x, width - 1));
1074 const int crop_y = std::max(0, std::min(settings.
y, height - 1));
1075 output_width = std::max(1, std::min(settings.
width, width - crop_x));
1076 output_height = std::max(1, std::min(settings.
height, height - crop_y));
1077 const size_t output_buffer_size =
static_cast<size_t>(output_width) * output_height * bytes_per_pixel;
1078 output_buffer =
static_cast<unsigned char*
>(aligned_malloc(output_buffer_size));
1079 if (!output_buffer) {
1081 throw OutOfMemory(
"Unable to allocate cropped capture frame buffer.", InputName());
1083 for (
int row = 0; row < output_height; ++row) {
1084 const unsigned char* source_row = buffer
1085 + (
static_cast<size_t>(crop_y + row) * width + crop_x) * bytes_per_pixel;
1086 unsigned char* dest_row = output_buffer +
static_cast<size_t>(row) * output_width * bytes_per_pixel;
1087 std::copy(source_row, source_row +
static_cast<size_t>(output_width) * bytes_per_pixel, dest_row);
1092 auto frame = std::make_shared<Frame>(number, output_width, output_height,
"#000000");
1093 frame->capture_timestamp = capture_timestamp;
1094 frame->AddImage(output_width, output_height, bytes_per_pixel, QImage::Format_RGBA8888, output_buffer);
1099 throw ReaderClosed(
"The ScreenCaptureReader was closed.");
1104 close_requested =
true;
1106 system_audio->Close();
1108 if (backend_reader) {
1109 backend_reader->Close();
1112 av_packet_free(&packet);
1115 av_frame_free(&source_frame);
1118 av_frame_free(&rgba_frame);
1121 sws_freeContext(sws_context);
1122 sws_context =
nullptr;
1124 if (codec_context) {
1125 avcodec_free_context(&codec_context);
1127 if (format_context) {
1128 avformat_close_input(&format_context);
1136 if (backend_reader) {
1137 return backend_reader->GetStats();
1143 const double fps = settings.
fps.
den != 0 ?
static_cast<double>(settings.
fps.
num) /
static_cast<double>(settings.
fps.
den) : 0.0;
1144 stats.
duration = fps > 0.0 ?
static_cast<double>(frames_read) / fps : 0.0;
1156 root[
"type"] =
"ScreenCaptureReader";
1157 root[
"backend"] = settings.
backend;
1158 root[
"display"] = settings.
display;
1159 root[
"x"] = settings.
x;
1160 root[
"y"] = settings.
y;
1161 root[
"width"] = settings.
width;
1162 root[
"height"] = settings.
height;
1163 root[
"fps"][
"num"] = settings.
fps.
num;
1164 root[
"fps"][
"den"] = settings.
fps.
den;
1171 root[
"options"] = Json::Value(Json::objectValue);
1172 for (
const auto& option : settings.
options) {
1173 root[
"options"][option.first] = option.second;
1182 }
catch (
const std::exception&) {
1183 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
1189 if (!root[
"backend"].isNull())
1191 if (!root[
"display"].isNull())
1192 settings.
display = root[
"display"].asString();
1193 if (!root[
"x"].isNull())
1194 settings.
x = root[
"x"].asInt();
1195 if (!root[
"y"].isNull())
1196 settings.
y = root[
"y"].asInt();
1197 if (!root[
"width"].isNull())
1198 settings.
width = root[
"width"].asInt();
1199 if (!root[
"height"].isNull())
1200 settings.
height = root[
"height"].asInt();
1201 if (!root[
"fps"].isNull() && root[
"fps"].isObject()) {
1202 if (!root[
"fps"][
"num"].isNull())
1203 settings.
fps.
num = root[
"fps"][
"num"].asInt();
1204 if (!root[
"fps"][
"den"].isNull())
1205 settings.
fps.
den = root[
"fps"][
"den"].asInt();
1207 if (!root[
"include_cursor"].isNull())
1209 if (!root[
"show_region"].isNull())
1210 settings.
show_region = root[
"show_region"].asBool();
1211 if (!root[
"capture_audio"].isNull())
1213 if (!root[
"audio_device"].isNull())
1214 settings.
audio_device = root[
"audio_device"].asString();
1215 if (!root[
"audio_sample_rate"].isNull())
1217 if (!root[
"audio_channels"].isNull())
1219 if (!root[
"options"].isNull() && root[
"options"].isObject()) {
1221 for (
const auto& key : root[
"options"].getMemberNames()) {
1222 settings.
options[key] = root[
"options"][key].asString();
1230 #if defined(__linux__) || defined(_WIN32)
1231 system_audio.reset();
1233 system_audio = std::make_unique<SystemAudioCapture>(settings);