18 #include <condition_variable>
27 #if defined(__linux__)
32 #include <libavdevice/avdevice.h>
33 #include <libavutil/imgutils.h>
40 #include <audioclient.h>
41 #include <mmdeviceapi.h>
50 #if defined(HAVE_WAYLAND_CAPTURE_PLUGIN) && defined(__linux__)
53 using WaylandBackendFactory = std::unique_ptr<ScreenCaptureReader::CaptureBackendReader> (*) (
56 void* load_wayland_capture_backend(std::string& error_message)
58 Dl_info library_info {};
59 if (dladdr(
reinterpret_cast<void*
>(load_wayland_capture_backend), &library_info)
60 && library_info.dli_fname) {
61 std::string library_path(library_info.dli_fname);
62 const auto separator = library_path.find_last_of(
'/');
63 if (separator != std::string::npos) {
64 const std::string module_path = library_path.substr(0, separator + 1)
65 +
"libopenshot-wayland-capture.so";
66 if (
void* module = dlopen(module_path.c_str(), RTLD_NOW | RTLD_LOCAL)) {
69 const char* error = dlerror();
70 error_message = error ? error :
"unable to load PipeWire support.";
74 void* module = dlopen(
"libopenshot-wayland-capture.so", RTLD_NOW | RTLD_LOCAL);
76 const char* error = dlerror();
77 error_message = error ? error :
"unable to load PipeWire support.";
84 #if defined(__linux__)
89 : settings(new_settings) {}
95 if (format_context)
return;
96 avdevice_register_all();
97 AVInputFormat* input_format =
const_cast<AVInputFormat*
>(av_find_input_format(
"pulse"));
99 throw InvalidOptions(
"FFmpeg PulseAudio input is unavailable for system audio capture.");
102 format_context = avformat_alloc_context();
103 if (!format_context) {
104 throw OutOfMemory(
"Unable to allocate system audio capture context.");
106 format_context->interrupt_callback.callback = InterruptCallback;
107 format_context->interrupt_callback.opaque = &close_requested;
109 AVDictionary* options =
nullptr;
110 av_dict_set(&options,
"sample_rate", std::to_string(settings.audio_sample_rate).c_str(), 0);
111 av_dict_set(&options,
"channels", std::to_string(settings.audio_channels).c_str(), 0);
112 const std::string device = settings.audio_device.empty() ?
"@DEFAULT_MONITOR@" : settings.audio_device;
113 const int open_result = avformat_open_input(&format_context, device.c_str(), input_format, &options);
114 av_dict_free(&options);
115 if (open_result < 0) {
116 throw InvalidFile(
"Unable to open system audio capture input: " + std::string(
av_err2str(open_result)), device);
118 if (avformat_find_stream_info(format_context,
nullptr) < 0) {
119 throw InvalidFile(
"Unable to read system audio capture stream information.", device);
121 for (
unsigned int index = 0; index < format_context->nb_streams; ++index) {
122 if (format_context->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
123 audio_stream =
static_cast<int>(index);
127 if (audio_stream < 0) {
128 throw InvalidFile(
"No audio stream found in system audio capture input.", device);
130 AVStream* stream = format_context->streams[audio_stream];
131 const AVCodec*
codec = avcodec_find_decoder(stream->codecpar->codec_id);
132 codec_context =
codec ? ffmpeg_get_codec_context(stream,
codec) : nullptr;
133 if (!codec_context || avcodec_open2(codec_context,
codec,
nullptr) < 0) {
134 throw InvalidCodec(
"Unable to open system audio capture decoder.", device);
136 packet = av_packet_alloc();
137 decoded_frame = av_frame_alloc();
138 if (!packet || !decoded_frame) {
139 throw OutOfMemory(
"Unable to allocate system audio capture buffers.");
141 settings.audio_sample_rate = codec_context->sample_rate > 0
142 ? codec_context->sample_rate : settings.audio_sample_rate;
143 channels.assign(settings.audio_channels, {});
144 close_requested =
false;
145 worker = std::thread(&SystemAudioCapture::CaptureLoop,
this);
150 close_requested =
true;
152 if (worker.joinable()) {
155 if (decoded_frame) av_frame_free(&decoded_frame);
156 if (packet) av_packet_free(&packet);
157 if (codec_context) avcodec_free_context(&codec_context);
158 if (format_context) avformat_close_input(&format_context);
163 int sample_count = 0;
164 for (int64_t frame_number = last_output_frame + 1; frame_number <= number; ++frame_number) {
166 frame_number, fps, settings.audio_sample_rate, settings.audio_channels);
168 last_output_frame = std::max(last_output_frame, number);
169 if (!frame || sample_count <= 0)
return;
171 std::unique_lock<std::mutex> lock(queue_mutex);
177 const auto wait_time = timeline_started
178 ? std::chrono::milliseconds(100)
179 : std::chrono::milliseconds(3000);
180 ready.wait_for(lock, wait_time, [
this, sample_count]() {
181 return close_requested || (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count);
183 if (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count) {
184 timeline_started =
true;
186 frame->SampleRate(settings.audio_sample_rate);
188 for (
int channel = 0; channel < settings.audio_channels; ++channel) {
189 std::vector<float> samples(sample_count, 0.0f);
190 if (channel <
static_cast<int>(channels.size())) {
191 const int available = std::min(sample_count,
static_cast<int>(channels[channel].size()));
192 for (
int index = 0; index < available; ++index) {
193 samples[index] = channels[channel].front();
194 channels[channel].pop_front();
197 frame->AddAudio(
true, channel, 0, samples.data(), sample_count, 1.0f);
203 std::lock_guard<std::mutex> lock(queue_mutex);
204 for (
auto& channel : channels) channel.clear();
205 last_output_frame = 0;
206 timeline_started =
false;
209 int SampleRate()
const {
return settings.audio_sample_rate; }
210 int Channels()
const {
return settings.audio_channels; }
213 static int InterruptCallback(
void* opaque)
215 const auto* requested =
static_cast<std::atomic<bool>*
>(opaque);
216 return requested && requested->load() ? 1 : 0;
219 float SampleAt(
const AVFrame* frame,
int channel,
int sample)
const
221 const AVSampleFormat format =
static_cast<AVSampleFormat
>(frame->format);
222 const bool planar = av_sample_fmt_is_planar(format) != 0;
223 const int source_channels = std::max(1,
225 codec_context->ch_layout.nb_channels
227 codec_context->channels
230 const int source_channel = std::min(channel, source_channels - 1);
231 const uint8_t* data = planar ? frame->extended_data[source_channel] : frame->extended_data[0];
232 const int offset = planar ? sample : sample * source_channels + source_channel;
234 case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
235 return (
static_cast<const uint8_t*
>(
static_cast<const void*
>(data))[offset] - 128) / 128.0f;
236 case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
237 return static_cast<const int16_t*
>(
static_cast<const void*
>(data))[offset] / 32768.0f;
238 case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
239 return static_cast<float>(
static_cast<const int32_t*
>(
static_cast<const void*
>(data))[offset] / 2147483648.0);
240 case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
241 return static_cast<const float*
>(
static_cast<const void*
>(data))[offset];
242 case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
243 return static_cast<float>(
static_cast<const double*
>(
static_cast<const void*
>(data))[offset]);
251 while (!close_requested) {
252 const int read_result = av_read_frame(format_context, packet);
253 if (read_result == AVERROR(EAGAIN))
continue;
254 if (read_result < 0)
break;
255 if (packet->stream_index != audio_stream) {
256 av_packet_unref(packet);
259 const int send_result = avcodec_send_packet(codec_context, packet);
260 av_packet_unref(packet);
261 if (send_result < 0)
continue;
262 while (avcodec_receive_frame(codec_context, decoded_frame) == 0) {
263 std::lock_guard<std::mutex> lock(queue_mutex);
264 for (
int channel = 0; channel < settings.audio_channels; ++channel) {
265 const size_t max_samples =
static_cast<size_t>(settings.audio_sample_rate) * 10;
266 for (
int sample = 0; sample < decoded_frame->nb_samples; ++sample) {
267 if (channels[channel].size() >= max_samples) channels[channel].pop_front();
268 channels[channel].push_back(SampleAt(decoded_frame, channel, sample));
271 av_frame_unref(decoded_frame);
278 AVFormatContext* format_context =
nullptr;
279 AVCodecContext* codec_context =
nullptr;
280 AVPacket* packet =
nullptr;
281 AVFrame* decoded_frame =
nullptr;
282 int audio_stream = -1;
283 std::atomic<bool> close_requested {
false };
285 std::mutex queue_mutex;
286 std::condition_variable ready;
287 std::vector<std::deque<float>> channels;
288 int64_t last_output_frame = 0;
289 bool timeline_started =
false;
291 #elif defined(_WIN32)
296 : settings(new_settings) {}
302 if (worker.joinable())
return;
303 close_requested =
false;
304 worker = std::thread(&SystemAudioCapture::CaptureLoop,
this);
305 std::unique_lock<std::mutex> lock(state_mutex);
306 state_ready.wait_for(lock, std::chrono::seconds(5), [
this]() {
return opened || failed; });
308 close_requested =
true;
310 if (worker.joinable()) worker.join();
311 throw InvalidOptions(error.empty() ?
"Unable to open WASAPI system audio loopback capture." : error);
317 close_requested =
true;
319 if (worker.joinable()) worker.join();
325 int sample_count = 0;
326 for (int64_t frame_number = last_output_frame + 1; frame_number <= number; ++frame_number) {
329 last_output_frame = std::max(last_output_frame, number);
330 if (!frame || sample_count <= 0)
return;
331 std::unique_lock<std::mutex> lock(queue_mutex);
335 const auto wait_time = timeline_started
336 ? std::chrono::milliseconds(100)
337 : std::chrono::milliseconds(3000);
338 ready.wait_for(lock, wait_time, [
this, sample_count]() {
339 return close_requested || (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count);
341 if (!channels.empty() &&
static_cast<int>(channels[0].size()) >= sample_count) {
342 timeline_started =
true;
344 frame->SampleRate(sample_rate);
346 for (
int channel = 0; channel < channel_count; ++channel) {
347 std::vector<float> samples(sample_count, 0.0f);
348 const int available = std::min(sample_count,
static_cast<int>(channels[channel].size()));
349 for (
int index = 0; index < available; ++index) {
350 samples[index] = channels[channel].front();
351 channels[channel].pop_front();
353 frame->AddAudio(
true, channel, 0, samples.data(), sample_count, 1.0f);
359 std::lock_guard<std::mutex> lock(queue_mutex);
360 for (
auto& channel : channels) channel.clear();
361 last_output_frame = 0;
362 timeline_started =
false;
365 int SampleRate()
const {
return sample_rate; }
366 int Channels()
const {
return channel_count; }
369 template <
typename T>
static void Release(T*& value)
371 if (value) { value->Release(); value =
nullptr; }
374 void Fail(
const std::string& message)
376 std::lock_guard<std::mutex> lock(state_mutex);
379 state_ready.notify_all();
384 IMMDeviceEnumerator* enumerator =
nullptr;
385 IMMDevice* device =
nullptr;
386 IAudioClient* client =
nullptr;
387 IAudioCaptureClient* capture =
nullptr;
388 WAVEFORMATEX* format =
nullptr;
389 const HRESULT com_result = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
390 const bool uninitialize_com = SUCCEEDED(com_result);
391 HRESULT result = CoCreateInstance(CLSID_MMDeviceEnumerator,
nullptr, CLSCTX_ALL,
392 IID_IMMDeviceEnumerator,
reinterpret_cast<void**
>(&enumerator));
393 if (SUCCEEDED(result)) {
394 result = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
396 if (SUCCEEDED(result)) {
397 result = device->Activate(IID_IAudioClient, CLSCTX_ALL,
nullptr,
reinterpret_cast<void**
>(&client));
399 if (SUCCEEDED(result)) result = client->GetMixFormat(&format);
400 if (SUCCEEDED(result)) {
401 result = client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK,
402 0, 0, format,
nullptr);
404 if (SUCCEEDED(result)) {
405 result = client->GetService(IID_IAudioCaptureClient,
reinterpret_cast<void**
>(&capture));
407 if (SUCCEEDED(result)) result = client->Start();
408 if (FAILED(result) || !format || !capture) {
409 Fail(
"Unable to initialize WASAPI system audio loopback capture (HRESULT " + std::to_string(result) +
").");
410 if (format) CoTaskMemFree(format);
411 Release(capture); Release(client); Release(device); Release(enumerator);
412 if (uninitialize_com) CoUninitialize();
416 sample_rate =
static_cast<int>(format->nSamplesPerSec);
417 channel_count = std::max(1, std::min(2,
static_cast<int>(format->nChannels)));
418 channels.assign(channel_count, {});
419 bool floating_point = format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT;
420 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE && format->cbSize >= 22) {
421 const auto* extensible =
reinterpret_cast<const WAVEFORMATEXTENSIBLE*
>(format);
422 floating_point = extensible->SubFormat.Data1 == WAVE_FORMAT_IEEE_FLOAT;
425 std::lock_guard<std::mutex> lock(state_mutex);
427 state_ready.notify_all();
430 while (!close_requested) {
431 UINT32 packet_frames = 0;
432 if (FAILED(capture->GetNextPacketSize(&packet_frames)))
break;
433 if (packet_frames == 0) {
434 std::this_thread::sleep_for(std::chrono::milliseconds(2));
437 BYTE* data =
nullptr;
440 if (FAILED(capture->GetBuffer(&data, &frames, &flags,
nullptr,
nullptr)))
break;
442 std::lock_guard<std::mutex> lock(queue_mutex);
443 for (UINT32 frame_index = 0; frame_index < frames; ++frame_index) {
444 for (
int channel = 0; channel < channel_count; ++channel) {
446 if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT) && data) {
447 const int offset =
static_cast<int>(frame_index) * format->nChannels + channel;
448 if (floating_point && format->wBitsPerSample == 32) {
449 sample =
reinterpret_cast<const float*
>(data)[offset];
450 }
else if (format->wBitsPerSample == 16) {
451 sample =
reinterpret_cast<const int16_t*
>(data)[offset] / 32768.0f;
452 }
else if (format->wBitsPerSample == 32) {
453 sample =
static_cast<float>(
reinterpret_cast<const int32_t*
>(data)[offset] / 2147483648.0);
456 const size_t max_samples =
static_cast<size_t>(sample_rate) * 10;
457 if (channels[channel].size() >= max_samples) channels[channel].pop_front();
458 channels[channel].push_back(sample);
462 capture->ReleaseBuffer(frames);
467 CoTaskMemFree(format);
468 Release(capture); Release(client); Release(device); Release(enumerator);
469 if (uninitialize_com) CoUninitialize();
473 std::atomic<bool> close_requested {
false };
475 std::mutex queue_mutex;
476 std::condition_variable ready;
477 std::vector<std::deque<float>> channels;
478 int64_t last_output_frame = 0;
479 bool timeline_started =
false;
480 int sample_rate = 48000;
481 int channel_count = 2;
482 std::mutex state_mutex;
483 std::condition_variable state_ready;
504 std::string fraction_to_string(
const Fraction& value)
506 std::stringstream stream;
507 stream << value.
num <<
"/" << value.
den;
511 void set_option(AVDictionary** options,
const std::string& key,
const std::string& value)
513 av_dict_set(options, key.c_str(), value.c_str(), 0);
516 bool option_enabled(
const std::map<std::string, std::string>& options,
const std::string& key)
518 const auto option = options.find(key);
519 if (option == options.end()) {
522 return option->second ==
"1" || option->second ==
"true" || option->second ==
"yes";
525 int option_int(
const std::map<std::string, std::string>& options,
const std::string& key,
int fallback)
527 const auto option = options.find(key);
528 if (option == options.end()) {
532 return std::stoi(option->second);
538 int capture_interrupt_callback(
void* opaque)
540 const auto* reader =
static_cast<std::atomic<bool>*
>(opaque);
541 return reader && reader->load() ? 1 : 0;
544 std::string avfoundation_video_name(
const std::string& input_name)
546 const size_t separator = input_name.find(
':');
547 return separator == std::string::npos ? input_name : input_name.substr(0, separator);
550 std::string avfoundation_audio_name(
const std::string& input_name)
552 const size_t separator = input_name.find(
':');
553 return separator == std::string::npos ?
"none" : input_name.substr(separator + 1);
556 bool resolve_avfoundation_video_index(
557 AVInputFormat* input_format,
558 const std::string& video_name,
559 std::string& video_index)
561 const auto is_digit = [](
unsigned char value) {
562 return std::isdigit(value) != 0;
564 if (video_name.empty()
565 || video_name ==
"default"
566 || video_name ==
"none"
567 || std::all_of(video_name.begin(), video_name.end(), is_digit)) {
571 AVDeviceInfoList* device_list =
nullptr;
572 const int result = avdevice_list_input_sources(input_format,
nullptr,
nullptr, &device_list);
573 if (result < 0 || !device_list) {
574 avdevice_free_list_devices(&device_list);
579 for (
int index = 0; index < device_list->nb_devices; ++index) {
580 const AVDeviceInfo* device = device_list->devices[index];
581 if (!device || !device->device_name) {
584 const std::string name = device->device_name;
585 const std::string description = device->device_description
586 ? device->device_description
587 : device->device_name;
588 if (video_name == name || video_name == description) {
589 video_index = std::all_of(name.begin(), name.end(), is_digit)
591 : std::to_string(index);
596 avdevice_free_list_devices(&device_list);
602 : settings(new_settings)
603 , backend_reader(nullptr)
604 , backend_module(nullptr)
609 , format_context(nullptr)
610 , codec_context(nullptr)
611 , source_frame(nullptr)
612 , rgba_frame(nullptr)
614 , sws_context(nullptr)
615 , close_requested(false)
616 , system_audio(nullptr)
623 #if defined(__linux__) || defined(_WIN32)
625 system_audio = std::make_unique<SystemAudioCapture>(settings);
628 if (UsesWaylandPortal()) {
629 #if defined(HAVE_WAYLAND_CAPTURE_PLUGIN) && defined(__linux__)
630 std::string module_error;
631 backend_module = load_wayland_capture_backend(module_error);
632 if (!backend_module) {
633 throw InvalidOptions(
"Wayland screen capture backend is unavailable: "
636 auto factory =
reinterpret_cast<WaylandBackendFactory
>(
637 dlsym(backend_module,
"OpenShotCreateWaylandScreenCaptureReader"));
639 const char* error = dlerror();
640 dlclose(backend_module);
641 backend_module =
nullptr;
642 throw InvalidOptions(
"Wayland screen capture backend is invalid: "
643 + std::string(error ? error :
"factory function is missing."));
646 backend_reader = factory(settings,
info);
648 dlclose(backend_module);
649 backend_module =
nullptr;
652 if (!backend_reader) {
653 dlclose(backend_module);
654 backend_module =
nullptr;
655 throw InvalidOptions(
"Wayland screen capture backend is unavailable.");
658 throw InvalidOptions(
"Wayland screen capture backend is unavailable in this build.");
666 #if defined(__linux__)
667 backend_reader.reset();
668 if (backend_module) {
669 dlclose(backend_module);
670 backend_module =
nullptr;
677 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
678 return backend_reader ? backend_reader->IsOpen() : is_open;
683 #if defined(__linux__)
687 #if defined(HAVE_WAYLAND_CAPTURE_PLUGIN)
693 #elif defined(_WIN32)
695 #elif defined(__APPLE__)
705 #if defined(__linux__)
709 avdevice_register_all();
711 && av_find_input_format(
"pulse") !=
nullptr;
712 #elif defined(_WIN32)
722 #if defined(__linux__)
723 const char* session = std::getenv(
"XDG_SESSION_TYPE");
727 if (!session || std::string(session) ==
"x11") {
730 #elif defined(_WIN32)
732 #elif defined(__APPLE__)
738 void ScreenCaptureReader::ValidateSettings()
const
741 throw InvalidOptions(
"Screen capture backend is not supported on this OS or session.");
743 if (!UsesFFmpegDevice() && !UsesWaylandPortal()) {
744 throw InvalidOptions(
"Screen capture backend is not implemented in this build.");
747 throw InvalidOptions(
"Screen capture requires a positive width and height.");
750 throw InvalidOptions(
"Screen capture requires a positive frame rate.");
753 throw InvalidOptions(
"System audio capture is not supported by this screen capture backend.");
756 throw InvalidSampleRate(
"System audio capture requires a sample rate of at least 8000 Hz.");
759 throw InvalidChannels(
"System audio capture requires one or two channels.");
763 bool ScreenCaptureReader::UsesFFmpegDevice()
const
768 || settings.
options.count(
"input_format_name");
771 bool ScreenCaptureReader::UsesWaylandPortal()
const
776 std::string ScreenCaptureReader::InputFormatName()
const
778 const auto override_format = settings.
options.find(
"input_format_name");
779 if (override_format != settings.
options.end()) {
780 return override_format->second;
789 return "avfoundation";
794 std::string ScreenCaptureReader::InputName()
const
796 if (InputFormatName() ==
"v4l2") {
797 return settings.
display.empty() ?
"/dev/video0" : settings.
display;
799 if (InputFormatName() ==
"dshow") {
802 if (InputFormatName() ==
"gdigrab") {
805 if (InputFormatName() ==
"avfoundation") {
806 return settings.
display.empty() ?
"Capture screen 0:none" : settings.
display;
809 std::string display = settings.
display;
810 if (display.empty()) {
811 const char* env_display = std::getenv(
"DISPLAY");
812 display = env_display ? env_display :
":0.0";
814 if (InputFormatName() ==
"x11grab" && settings.
options.count(
"window_id")) {
818 std::stringstream input;
819 input << display <<
"+" << settings.
x <<
"," << settings.
y;
823 void ScreenCaptureReader::PopulateInfo()
855 if (backend_reader) {
856 if (backend_reader->IsOpen())
return;
857 manual_system_audio =
false;
859 system_audio->Open();
865 backend_reader->Open();
867 if (system_audio) system_audio->Close();
875 manual_system_audio =
false;
877 system_audio->Open();
882 close_requested =
false;
887 if (system_audio) system_audio->Close();
893 void ScreenCaptureReader::OpenDevice()
895 avdevice_register_all();
897 AVInputFormat* input_format =
const_cast<AVInputFormat*
>(av_find_input_format(InputFormatName().c_str()));
898 std::string input_name = InputName();
900 throw InvalidOptions(
"FFmpeg input device is not available: " + InputFormatName(), input_name);
903 format_context = avformat_alloc_context();
904 if (!format_context) {
905 throw OutOfMemory(
"Unable to allocate capture format context.", input_name);
907 format_context->interrupt_callback.callback = capture_interrupt_callback;
908 format_context->interrupt_callback.opaque = &close_requested;
910 AVDictionary* options =
nullptr;
911 const bool use_device_defaults = settings.
options.count(
"use_device_defaults") > 0;
912 const bool post_capture_crop = option_enabled(settings.
options,
"crop_after_capture");
913 if (!use_device_defaults && !post_capture_crop) {
914 set_option(&options,
"framerate", fraction_to_string(settings.
fps));
915 set_option(&options,
"video_size", std::to_string(settings.
width) +
"x" + std::to_string(settings.
height));
916 }
else if (post_capture_crop) {
917 const int source_width = option_int(settings.
options,
"crop_source_width", settings.
width);
918 const int source_height = option_int(settings.
options,
"crop_source_height", settings.
height);
919 set_option(&options,
"framerate", fraction_to_string(settings.
fps));
920 set_option(&options,
"video_size", std::to_string(source_width) +
"x" + std::to_string(source_height));
922 if (InputFormatName() ==
"x11grab") {
923 set_option(&options,
"draw_mouse", settings.
include_cursor ?
"1" :
"0");
924 set_option(&options,
"show_region", settings.
show_region ?
"1" :
"0");
925 }
else if (InputFormatName() ==
"gdigrab") {
926 set_option(&options,
"draw_mouse", settings.
include_cursor ?
"1" :
"0");
927 set_option(&options,
"show_region", settings.
show_region ?
"1" :
"0");
928 set_option(&options,
"offset_x", std::to_string(settings.
x));
929 set_option(&options,
"offset_y", std::to_string(settings.
y));
930 }
else if (InputFormatName() ==
"avfoundation") {
931 set_option(&options,
"capture_cursor", settings.
include_cursor ?
"1" :
"0");
932 std::string video_index;
933 if (resolve_avfoundation_video_index(input_format, avfoundation_video_name(input_name), video_index)) {
934 set_option(&options,
"video_device_index", video_index);
935 input_name =
":" + avfoundation_audio_name(input_name);
938 for (
const auto& option : settings.
options) {
939 if (option.first ==
"input_format_name"
940 || option.first ==
"use_device_defaults"
941 || option.first ==
"crop_after_capture"
942 || option.first ==
"crop_source_width"
943 || option.first ==
"crop_source_height") {
946 set_option(&options, option.first, option.second);
949 const int result = avformat_open_input(&format_context, input_name.c_str(), input_format, &options);
950 av_dict_free(&options);
952 throw InvalidFile(
"Unable to open screen capture input: " + std::string(
av_err2str(result)), input_name);
956 void ScreenCaptureReader::OpenDecoder()
958 if (avformat_find_stream_info(format_context,
nullptr) < 0) {
959 throw InvalidFile(
"Unable to read capture stream information.", InputName());
962 for (
unsigned int index = 0; index < format_context->nb_streams; ++index) {
963 if (format_context->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
964 video_stream =
static_cast<int>(index);
968 if (video_stream < 0) {
969 throw InvalidFile(
"No video stream found in capture input.", InputName());
972 AVStream* stream = format_context->streams[video_stream];
973 const AVCodec*
codec = avcodec_find_decoder(stream->codecpar->codec_id);
975 throw InvalidCodec(
"No decoder available for capture stream.", InputName());
978 codec_context = ffmpeg_get_codec_context(stream,
codec);
979 if (!codec_context || avcodec_open2(codec_context,
codec,
nullptr) < 0) {
980 throw InvalidCodec(
"Unable to open capture stream decoder.", InputName());
983 info.
width = codec_context->width > 0 ? codec_context->width : settings.
width;
984 info.
height = codec_context->height > 0 ? codec_context->height : settings.
height;
985 if (option_enabled(settings.
options,
"crop_after_capture")) {
993 if (codec_context->framerate.num > 0 && codec_context->framerate.den > 0) {
994 info.
fps =
Fraction(codec_context->framerate.num, codec_context->framerate.den);
996 }
else if (stream->avg_frame_rate.num > 0 && stream->avg_frame_rate.den > 0) {
997 info.
fps =
Fraction(stream->avg_frame_rate.num, stream->avg_frame_rate.den);
999 }
else if (stream->r_frame_rate.num > 0 && stream->r_frame_rate.den > 0) {
1000 info.
fps =
Fraction(stream->r_frame_rate.num, stream->r_frame_rate.den);
1004 source_frame = av_frame_alloc();
1005 rgba_frame = av_frame_alloc();
1006 packet = av_packet_alloc();
1007 if (!source_frame || !rgba_frame || !packet) {
1008 throw OutOfMemory(
"Unable to allocate capture decoder frames.", InputName());
1014 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
1015 if (backend_reader) {
1016 if (!backend_reader->IsOpen()) {
1017 throw ReaderClosed(
"The ScreenCaptureReader is closed. Call Open() before GetFrame().");
1019 auto frame = backend_reader->GetFrame(number);
1020 if (system_audio && !manual_system_audio) system_audio->AddFrameAudio(frame, number,
info.
fps);
1024 throw ReaderClosed(
"The ScreenCaptureReader is closed. Call Open() before GetFrame().");
1027 auto frame = DecodeNextFrame(number);
1028 if (system_audio && !manual_system_audio) system_audio->AddFrameAudio(frame, number,
info.
fps);
1035 system_audio->AddFrameAudio(frame, output_frame_number,
info.
fps);
1041 manual_system_audio =
true;
1043 system_audio->Reset();
1047 std::shared_ptr<Frame> ScreenCaptureReader::DecodeNextFrame(int64_t number)
1049 while (!close_requested) {
1050 const int read_result = av_read_frame(format_context, packet);
1051 if (read_result == AVERROR(EAGAIN)) {
1052 std::this_thread::sleep_for(std::chrono::milliseconds(5));
1055 if (read_result < 0) {
1056 const std::string message = frames_read > 0
1057 ?
"Capture input ended after " + std::to_string(frames_read) +
" frame(s): "
1058 :
"Capture input ended before a frame could be read: ";
1062 if (packet->stream_index != video_stream) {
1063 av_packet_unref(packet);
1068 const int64_t packet_timestamp = packet->pts != AV_NOPTS_VALUE ? packet->pts : packet->dts;
1069 const int send_result = avcodec_send_packet(codec_context, packet);
1070 av_packet_unref(packet);
1071 if (send_result < 0) {
1075 const int receive_result = avcodec_receive_frame(codec_context, source_frame);
1076 if (receive_result == AVERROR(EAGAIN)) {
1079 if (receive_result < 0) {
1080 throw InvalidFile(
"Unable to decode capture frame: " + std::string(
av_err2str(receive_result)), InputName());
1083 const AVStream* stream = format_context->streams[video_stream];
1084 int64_t frame_timestamp = source_frame->best_effort_timestamp;
1085 if (frame_timestamp == AV_NOPTS_VALUE) {
1086 frame_timestamp = source_frame->pts;
1088 if (frame_timestamp == AV_NOPTS_VALUE) {
1089 frame_timestamp = packet_timestamp;
1091 double capture_timestamp = std::numeric_limits<double>::quiet_NaN();
1092 if (frame_timestamp != AV_NOPTS_VALUE && stream) {
1093 capture_timestamp =
static_cast<double>(frame_timestamp) * av_q2d(stream->time_base);
1096 const int width = source_frame->width > 0 ? source_frame->width :
info.
width;
1097 const int height = source_frame->height > 0 ? source_frame->height :
info.
height;
1100 sws_context = sws_getCachedContext(
1113 throw InvalidFile(
"Unable to create capture pixel conversion context.", InputName());
1116 const int bytes_per_pixel = 4;
1117 const size_t buffer_size =
static_cast<size_t>(width) * height * bytes_per_pixel;
1118 unsigned char* buffer =
static_cast<unsigned char*
>(aligned_malloc(buffer_size));
1120 throw OutOfMemory(
"Unable to allocate capture frame buffer.", InputName());
1123 av_image_fill_arrays(rgba_frame->data, rgba_frame->linesize, buffer, AV_PIX_FMT_RGBA, width, height, 1);
1124 const int scaled_lines = sws_scale(sws_context, source_frame->data, source_frame->linesize, 0, height, rgba_frame->data, rgba_frame->linesize);
1125 av_frame_unref(source_frame);
1127 if (scaled_lines <= 0) {
1132 int output_width = width;
1133 int output_height = height;
1134 unsigned char* output_buffer = buffer;
1135 if (option_enabled(settings.
options,
"crop_after_capture")) {
1136 const int crop_x = std::max(0, std::min(settings.
x, width - 1));
1137 const int crop_y = std::max(0, std::min(settings.
y, height - 1));
1138 output_width = std::max(1, std::min(settings.
width, width - crop_x));
1139 output_height = std::max(1, std::min(settings.
height, height - crop_y));
1140 const size_t output_buffer_size =
static_cast<size_t>(output_width) * output_height * bytes_per_pixel;
1141 output_buffer =
static_cast<unsigned char*
>(aligned_malloc(output_buffer_size));
1142 if (!output_buffer) {
1144 throw OutOfMemory(
"Unable to allocate cropped capture frame buffer.", InputName());
1146 for (
int row = 0; row < output_height; ++row) {
1147 const unsigned char* source_row = buffer
1148 + (
static_cast<size_t>(crop_y + row) * width + crop_x) * bytes_per_pixel;
1149 unsigned char* dest_row = output_buffer +
static_cast<size_t>(row) * output_width * bytes_per_pixel;
1150 std::copy(source_row, source_row +
static_cast<size_t>(output_width) * bytes_per_pixel, dest_row);
1155 auto frame = std::make_shared<Frame>(number, output_width, output_height,
"#000000");
1156 frame->capture_timestamp = capture_timestamp;
1157 frame->AddImage(output_width, output_height, bytes_per_pixel, QImage::Format_RGBA8888, output_buffer);
1162 throw ReaderClosed(
"The ScreenCaptureReader was closed.");
1170 close_requested =
true;
1171 if (backend_reader) {
1172 backend_reader->Close();
1177 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
1179 system_audio->Close();
1182 av_packet_free(&packet);
1185 av_frame_free(&source_frame);
1188 av_frame_free(&rgba_frame);
1191 sws_freeContext(sws_context);
1192 sws_context =
nullptr;
1194 if (codec_context) {
1195 avcodec_free_context(&codec_context);
1197 if (format_context) {
1198 avformat_close_input(&format_context);
1206 if (backend_reader) {
1207 return backend_reader->GetStats();
1213 const double fps = settings.
fps.
den != 0 ?
static_cast<double>(settings.
fps.
num) /
static_cast<double>(settings.
fps.
den) : 0.0;
1214 stats.
duration = fps > 0.0 ?
static_cast<double>(frames_read) / fps : 0.0;
1226 root[
"type"] =
"ScreenCaptureReader";
1227 root[
"backend"] = settings.
backend;
1228 root[
"display"] = settings.
display;
1229 root[
"x"] = settings.
x;
1230 root[
"y"] = settings.
y;
1231 root[
"width"] = settings.
width;
1232 root[
"height"] = settings.
height;
1233 root[
"fps"][
"num"] = settings.
fps.
num;
1234 root[
"fps"][
"den"] = settings.
fps.
den;
1241 root[
"options"] = Json::Value(Json::objectValue);
1242 for (
const auto& option : settings.
options) {
1243 root[
"options"][option.first] = option.second;
1252 }
catch (
const std::exception&) {
1253 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
1259 if (!root[
"backend"].isNull())
1261 if (!root[
"display"].isNull())
1262 settings.
display = root[
"display"].asString();
1263 if (!root[
"x"].isNull())
1264 settings.
x = root[
"x"].asInt();
1265 if (!root[
"y"].isNull())
1266 settings.
y = root[
"y"].asInt();
1267 if (!root[
"width"].isNull())
1268 settings.
width = root[
"width"].asInt();
1269 if (!root[
"height"].isNull())
1270 settings.
height = root[
"height"].asInt();
1271 if (!root[
"fps"].isNull() && root[
"fps"].isObject()) {
1272 if (!root[
"fps"][
"num"].isNull())
1273 settings.
fps.
num = root[
"fps"][
"num"].asInt();
1274 if (!root[
"fps"][
"den"].isNull())
1275 settings.
fps.
den = root[
"fps"][
"den"].asInt();
1277 if (!root[
"include_cursor"].isNull())
1279 if (!root[
"show_region"].isNull())
1280 settings.
show_region = root[
"show_region"].asBool();
1281 if (!root[
"capture_audio"].isNull())
1283 if (!root[
"audio_device"].isNull())
1284 settings.
audio_device = root[
"audio_device"].asString();
1285 if (!root[
"audio_sample_rate"].isNull())
1287 if (!root[
"audio_channels"].isNull())
1289 if (!root[
"options"].isNull() && root[
"options"].isObject()) {
1291 for (
const auto& key : root[
"options"].getMemberNames()) {
1292 settings.
options[key] = root[
"options"][key].asString();
1300 #if defined(__linux__) || defined(_WIN32)
1301 system_audio.reset();
1303 system_audio = std::make_unique<SystemAudioCapture>(settings);
Header file for all Exception classes.
#define av_err2str(errnum)
Header file for Frame class.
Header file for QtUtilities (compatibiity overlay)
Header file for live screen capture readers.
void AddFrameAudio(const std::shared_ptr< Frame > &, int64_t, const Fraction &)
SystemAudioCapture(const ScreenCaptureSettings &)
This class represents a fraction.
int num
Numerator for the fraction.
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
void Reduce()
Reduce this fraction (i.e. 640/480 = 4/3)
Fraction Reciprocal() const
Return the reciprocal as a Fraction.
int den
Denominator for the fraction.
int GetSamplesPerFrame(openshot::Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Exception when an invalid # of audio channels are detected.
Exception when no valid codec is found for a file.
Exception for files that can not be found or opened.
Exception for invalid JSON.
Exception when invalid encoding options are used.
Exception when invalid sample rate is detected during encoding.
Exception when memory could not be allocated.
openshot::ReaderInfo info
Information about the current media file.
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
std::recursive_mutex getFrameMutex
Mutex for multiple threads.
Exception when a reader is closed, and a frame is requested.
void SetJson(const std::string value) override
Load JSON string into this object.
bool IsOpen() override
Determine if reader is open or closed.
~ScreenCaptureReader() override
openshot::CaptureReaderStats GetStats() const
void Close() override
Close the reader (and any resources it was consuming)
static ScreenCaptureBackend DefaultBackend()
static bool IsBackendSupported(ScreenCaptureBackend backend)
ScreenCaptureReader(const ScreenCaptureSettings &settings)
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
void AddSystemAudio(std::shared_ptr< openshot::Frame > frame, int64_t output_frame_number)
Json::Value JsonValue() const override
Generate Json::Value for this object.
std::shared_ptr< openshot::Frame > GetFrame(int64_t number) override
std::string Json() const override
Generate JSON string of this object.
void Open() override
Open the reader (and start consuming resources, such as images or video files)
static bool IsSystemAudioSupported(ScreenCaptureBackend backend)
This namespace is the default namespace for all code in the openshot library.
void aligned_free(void *ptr)
@ SCREEN_CAPTURE_MAC_AVFOUNDATION
@ SCREEN_CAPTURE_WINDOWS_GDI
const Json::Value stringToJson(const std::string value)
This struct contains info about a media file, such as height, width, frames per second,...
int audio_bit_rate
The bit rate of the audio stream (in bytes)
int video_bit_rate
The bit rate of the video stream (in bytes)
bool has_single_image
Determines if this file only contains a single image.
float duration
Length of time (in seconds)
openshot::Fraction audio_timebase
The audio timebase determines how long each audio packet should be played.
int width
The width of the video (in pixesl)
int channels
The number of audio channels used in the audio stream.
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
openshot::Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3)
int height
The height of the video (in pixels)
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
int64_t video_length
The number of frames in the video stream.
std::string acodec
The name of the audio codec used to encode / decode the video stream.
std::string vcodec
The name of the video codec used to encode / decode the video stream.
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square)
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
bool has_video
Determines if this file has a video stream.
bool has_audio
Determines if this file has an audio stream.
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
int video_stream_index
The index of the video stream.
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
int audio_stream_index
The index of the audio stream.
int64_t file_size
Size of file (in bytes)
std::map< std::string, std::string > options
ScreenCaptureBackend backend