OpenShot Library | libopenshot  0.7.0
ScreenCaptureReader.cpp
Go to the documentation of this file.
1 
9 // Copyright (c) 2008-2026 OpenShot Studios, LLC
10 //
11 // SPDX-License-Identifier: LGPL-3.0-or-later
12 
13 #include "ScreenCaptureReader.h"
14 
15 #include <algorithm>
16 #include <cctype>
17 #include <chrono>
18 #include <condition_variable>
19 #include <cstdlib>
20 #include <deque>
21 #include <limits>
22 #include <mutex>
23 #include <sstream>
24 #include <thread>
25 #include <vector>
26 
27 extern "C" {
28  #include <libavdevice/avdevice.h>
29  #include <libavutil/imgutils.h>
30 }
31 
32 #if defined(_WIN32)
33  // Instantiate the Core Audio COM GUIDs in this translation unit. Older
34  // MinGW-w64 uuid import libraries do not provide all WASAPI identifiers.
35  #include <initguid.h>
36  #include <audioclient.h>
37  #include <mmdeviceapi.h>
38 #endif
39 
40 #include "Exceptions.h"
41 #include "Frame.h"
42 #include "QtUtilities.h"
43 
44 using namespace openshot;
45 
46 #if defined(__linux__)
48 {
49 public:
50  explicit SystemAudioCapture(const ScreenCaptureSettings& new_settings)
51  : settings(new_settings) {}
52 
53  ~SystemAudioCapture() { Close(); }
54 
55  void Open()
56  {
57  if (format_context) return;
58  avdevice_register_all();
59  AVInputFormat* input_format = const_cast<AVInputFormat*>(av_find_input_format("pulse"));
60  if (!input_format) {
61  throw InvalidOptions("FFmpeg PulseAudio input is unavailable for system audio capture.");
62  }
63 
64  format_context = avformat_alloc_context();
65  if (!format_context) {
66  throw OutOfMemory("Unable to allocate system audio capture context.");
67  }
68  format_context->interrupt_callback.callback = InterruptCallback;
69  format_context->interrupt_callback.opaque = &close_requested;
70 
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);
79  }
80  if (avformat_find_stream_info(format_context, nullptr) < 0) {
81  throw InvalidFile("Unable to read system audio capture stream information.", device);
82  }
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);
86  break;
87  }
88  }
89  if (audio_stream < 0) {
90  throw InvalidFile("No audio stream found in system audio capture input.", device);
91  }
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);
97  }
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.");
102  }
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);
108  }
109 
110  void Close()
111  {
112  close_requested = true;
113  ready.notify_all();
114  if (worker.joinable()) {
115  worker.join();
116  }
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);
121  }
122 
123  void AddFrameAudio(const std::shared_ptr<Frame>& frame, int64_t number, const Fraction& fps)
124  {
125  int sample_count = 0;
126  for (int64_t frame_number = last_output_frame + 1; frame_number <= number; ++frame_number) {
127  sample_count += Frame::GetSamplesPerFrame(
128  frame_number, fps, settings.audio_sample_rate, settings.audio_channels);
129  }
130  last_output_frame = std::max(last_output_frame, number);
131  if (!frame || sample_count <= 0) return;
132 
133  std::unique_lock<std::mutex> lock(queue_mutex);
134  // The capture backend commonly delivers its first buffer later than the
135  // first video frame. Writing silence after the old 100 ms timeout moved
136  // every subsequently-delivered sample later on the recording timeline.
137  // Allow the first frame to establish the audio epoch before falling back
138  // to the short steady-state wait used for later frames.
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);
144  });
145  if (!channels.empty() && static_cast<int>(channels[0].size()) >= sample_count) {
146  timeline_started = true;
147  }
148  frame->SampleRate(settings.audio_sample_rate);
149  frame->ChannelsLayout(settings.audio_channels == 1 ? LAYOUT_MONO : LAYOUT_STEREO);
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();
157  }
158  }
159  frame->AddAudio(true, channel, 0, samples.data(), sample_count, 1.0f);
160  }
161  }
162 
163  void Reset()
164  {
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;
169  }
170 
171  int SampleRate() const { return settings.audio_sample_rate; }
172  int Channels() const { return settings.audio_channels; }
173 
174 private:
175  static int InterruptCallback(void* opaque)
176  {
177  const auto* requested = static_cast<std::atomic<bool>*>(opaque);
178  return requested && requested->load() ? 1 : 0;
179  }
180 
181  float SampleAt(const AVFrame* frame, int channel, int sample) const
182  {
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,
186 #if HAVE_CH_LAYOUT
187  codec_context->ch_layout.nb_channels
188 #else
189  codec_context->channels
190 #endif
191  );
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;
195  switch (format) {
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]);
206  default:
207  return 0.0f;
208  }
209  }
210 
211  void CaptureLoop()
212  {
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);
219  continue;
220  }
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));
231  }
232  }
233  av_frame_unref(decoded_frame);
234  ready.notify_all();
235  }
236  }
237  }
238 
239  ScreenCaptureSettings settings;
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 };
246  std::thread worker;
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;
252 };
253 #elif defined(_WIN32)
255 {
256 public:
257  explicit SystemAudioCapture(const ScreenCaptureSettings& new_settings)
258  : settings(new_settings) {}
259 
260  ~SystemAudioCapture() { Close(); }
261 
262  void Open()
263  {
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; });
269  if (!opened) {
270  close_requested = true;
271  lock.unlock();
272  if (worker.joinable()) worker.join();
273  throw InvalidOptions(error.empty() ? "Unable to open WASAPI system audio loopback capture." : error);
274  }
275  }
276 
277  void Close()
278  {
279  close_requested = true;
280  ready.notify_all();
281  if (worker.joinable()) worker.join();
282  opened = false;
283  }
284 
285  void AddFrameAudio(const std::shared_ptr<Frame>& frame, int64_t number, const Fraction& fps)
286  {
287  int sample_count = 0;
288  for (int64_t frame_number = last_output_frame + 1; frame_number <= number; ++frame_number) {
289  sample_count += Frame::GetSamplesPerFrame(frame_number, fps, sample_rate, channel_count);
290  }
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);
294  // WASAPI can take longer than one video-frame interval to make its first
295  // loopback packet available. Keep that startup latency out of the encoded
296  // media timeline by waiting for the first complete frame of audio.
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);
302  });
303  if (!channels.empty() && static_cast<int>(channels[0].size()) >= sample_count) {
304  timeline_started = true;
305  }
306  frame->SampleRate(sample_rate);
307  frame->ChannelsLayout(channel_count == 1 ? LAYOUT_MONO : LAYOUT_STEREO);
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();
314  }
315  frame->AddAudio(true, channel, 0, samples.data(), sample_count, 1.0f);
316  }
317  }
318 
319  void Reset()
320  {
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;
325  }
326 
327  int SampleRate() const { return sample_rate; }
328  int Channels() const { return channel_count; }
329 
330 private:
331  template <typename T> static void Release(T*& value)
332  {
333  if (value) { value->Release(); value = nullptr; }
334  }
335 
336  void Fail(const std::string& message)
337  {
338  std::lock_guard<std::mutex> lock(state_mutex);
339  error = message;
340  failed = true;
341  state_ready.notify_all();
342  }
343 
344  void CaptureLoop()
345  {
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);
357  }
358  if (SUCCEEDED(result)) {
359  result = device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&client));
360  }
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);
365  }
366  if (SUCCEEDED(result)) {
367  result = client->GetService(IID_IAudioCaptureClient, reinterpret_cast<void**>(&capture));
368  }
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();
375  return;
376  }
377 
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;
385  }
386  {
387  std::lock_guard<std::mutex> lock(state_mutex);
388  opened = true;
389  state_ready.notify_all();
390  }
391 
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));
397  continue;
398  }
399  BYTE* data = nullptr;
400  UINT32 frames = 0;
401  DWORD flags = 0;
402  if (FAILED(capture->GetBuffer(&data, &frames, &flags, nullptr, nullptr))) break;
403  {
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) {
407  float sample = 0.0f;
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);
416  }
417  }
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);
421  }
422  }
423  }
424  capture->ReleaseBuffer(frames);
425  ready.notify_all();
426  }
427 
428  client->Stop();
429  CoTaskMemFree(format);
430  Release(capture); Release(client); Release(device); Release(enumerator);
431  if (uninitialize_com) CoUninitialize();
432  }
433 
434  ScreenCaptureSettings settings;
435  std::atomic<bool> close_requested { false };
436  std::thread worker;
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;
446  bool opened = false;
447  bool failed = false;
448  std::string error;
449 };
450 #else
452 {
453 public:
455  void Open() {}
456  void Close() {}
457  void AddFrameAudio(const std::shared_ptr<Frame>&, int64_t, const Fraction&) {}
458  void Reset() {}
459  int SampleRate() const { return 0; }
460  int Channels() const { return 0; }
461 };
462 #endif
463 
464 namespace
465 {
466  std::string fraction_to_string(const Fraction& value)
467  {
468  std::stringstream stream;
469  stream << value.num << "/" << value.den;
470  return stream.str();
471  }
472 
473  void set_option(AVDictionary** options, const std::string& key, const std::string& value)
474  {
475  av_dict_set(options, key.c_str(), value.c_str(), 0);
476  }
477 
478  bool option_enabled(const std::map<std::string, std::string>& options, const std::string& key)
479  {
480  const auto option = options.find(key);
481  if (option == options.end()) {
482  return false;
483  }
484  return option->second == "1" || option->second == "true" || option->second == "yes";
485  }
486 
487  int option_int(const std::map<std::string, std::string>& options, const std::string& key, int fallback)
488  {
489  const auto option = options.find(key);
490  if (option == options.end()) {
491  return fallback;
492  }
493  try {
494  return std::stoi(option->second);
495  } catch (...) {
496  return fallback;
497  }
498  }
499 
500  int capture_interrupt_callback(void* opaque)
501  {
502  const auto* reader = static_cast<std::atomic<bool>*>(opaque);
503  return reader && reader->load() ? 1 : 0;
504  }
505 
506  std::string avfoundation_video_name(const std::string& input_name)
507  {
508  const size_t separator = input_name.find(':');
509  return separator == std::string::npos ? input_name : input_name.substr(0, separator);
510  }
511 
512  std::string avfoundation_audio_name(const std::string& input_name)
513  {
514  const size_t separator = input_name.find(':');
515  return separator == std::string::npos ? "none" : input_name.substr(separator + 1);
516  }
517 
518  bool resolve_avfoundation_video_index(
519  AVInputFormat* input_format,
520  const std::string& video_name,
521  std::string& video_index)
522  {
523  const auto is_digit = [](unsigned char value) {
524  return std::isdigit(value) != 0;
525  };
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)) {
530  return false;
531  }
532 
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);
537  return false;
538  }
539 
540  bool found = false;
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) {
544  continue;
545  }
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)
552  ? name
553  : std::to_string(index);
554  found = true;
555  break;
556  }
557  }
558  avdevice_free_list_devices(&device_list);
559  return found;
560  }
561 }
562 
563 #if defined(HAVE_WAYLAND_CAPTURE)
564 std::unique_ptr<ScreenCaptureReader::CaptureBackendReader> CreateWaylandScreenCaptureReader(
565  const ScreenCaptureSettings& settings,
566  ReaderInfo& info);
567 #endif
568 
570  : settings(new_settings)
571  , backend_reader(nullptr)
572  , is_open(false)
573  , video_stream(-1)
574  , frames_read(0)
575  , dropped_packets(0)
576  , format_context(nullptr)
577  , codec_context(nullptr)
578  , source_frame(nullptr)
579  , rgba_frame(nullptr)
580  , packet(nullptr)
581  , sws_context(nullptr)
582  , close_requested(false)
583  , system_audio(nullptr)
584 {
585  if (settings.backend == SCREEN_CAPTURE_AUTO) {
586  settings.backend = DefaultBackend();
587  }
588  ValidateSettings();
589  PopulateInfo();
590 #if defined(__linux__) || defined(_WIN32)
591  if (settings.capture_audio) {
592  system_audio = std::make_unique<SystemAudioCapture>(settings);
593  }
594 #endif
595  if (UsesWaylandPortal()) {
596  #if defined(HAVE_WAYLAND_CAPTURE)
597  backend_reader = CreateWaylandScreenCaptureReader(settings, info);
598  if (!backend_reader) {
599  throw InvalidOptions("Wayland screen capture backend is unavailable in this build.");
600  }
601  #else
602  throw InvalidOptions("Wayland screen capture backend is unavailable in this build.");
603  #endif
604  }
605 }
606 
608 {
609  Close();
610 }
611 
613 {
614  return backend_reader ? backend_reader->IsOpen() : is_open;
615 }
616 
618 {
619 #if defined(__linux__)
620  if (backend == SCREEN_CAPTURE_X11 || backend == SCREEN_CAPTURE_AUTO) {
621  return true;
622  }
623 #if defined(HAVE_WAYLAND_CAPTURE)
624  if (backend == SCREEN_CAPTURE_WAYLAND) {
625  return true;
626  }
627 #endif
628  return false;
629 #elif defined(_WIN32)
630  return backend == SCREEN_CAPTURE_WINDOWS_GDI || backend == SCREEN_CAPTURE_AUTO;
631 #elif defined(__APPLE__)
632  return backend == SCREEN_CAPTURE_MAC_AVFOUNDATION || backend == SCREEN_CAPTURE_AUTO;
633 #else
634  (void) backend;
635  return false;
636 #endif
637 }
638 
640 {
641 #if defined(__linux__)
642  if (backend == SCREEN_CAPTURE_AUTO) {
643  backend = DefaultBackend();
644  }
645  avdevice_register_all();
646  return (backend == SCREEN_CAPTURE_X11 || backend == SCREEN_CAPTURE_WAYLAND)
647  && av_find_input_format("pulse") != nullptr;
648 #elif defined(_WIN32)
649  return backend == SCREEN_CAPTURE_AUTO || backend == SCREEN_CAPTURE_WINDOWS_GDI;
650 #else
651  (void) backend;
652  return false;
653 #endif
654 }
655 
657 {
658 #if defined(__linux__)
659  const char* session = std::getenv("XDG_SESSION_TYPE");
660  if (session && std::string(session) == "wayland" && IsBackendSupported(SCREEN_CAPTURE_WAYLAND)) {
661  return SCREEN_CAPTURE_WAYLAND;
662  }
663  if (!session || std::string(session) == "x11") {
664  return SCREEN_CAPTURE_X11;
665  }
666 #elif defined(_WIN32)
668 #elif defined(__APPLE__)
670 #endif
671  return SCREEN_CAPTURE_AUTO;
672 }
673 
674 void ScreenCaptureReader::ValidateSettings() const
675 {
676  if (!IsBackendSupported(settings.backend)) {
677  throw InvalidOptions("Screen capture backend is not supported on this OS or session.");
678  }
679  if (!UsesFFmpegDevice() && !UsesWaylandPortal()) {
680  throw InvalidOptions("Screen capture backend is not implemented in this build.");
681  }
682  if (settings.width <= 0 || settings.height <= 0) {
683  throw InvalidOptions("Screen capture requires a positive width and height.");
684  }
685  if (settings.fps.num <= 0 || settings.fps.den <= 0) {
686  throw InvalidOptions("Screen capture requires a positive frame rate.");
687  }
688  if (settings.capture_audio && !IsSystemAudioSupported(settings.backend)) {
689  throw InvalidOptions("System audio capture is not supported by this screen capture backend.");
690  }
691  if (settings.audio_sample_rate < 8000) {
692  throw InvalidSampleRate("System audio capture requires a sample rate of at least 8000 Hz.");
693  }
694  if (settings.audio_channels < 1 || settings.audio_channels > 2) {
695  throw InvalidChannels("System audio capture requires one or two channels.");
696  }
697 }
698 
699 bool ScreenCaptureReader::UsesFFmpegDevice() const
700 {
701  return settings.backend == SCREEN_CAPTURE_X11
702  || settings.backend == SCREEN_CAPTURE_WINDOWS_GDI
704  || settings.options.count("input_format_name");
705 }
706 
707 bool ScreenCaptureReader::UsesWaylandPortal() const
708 {
709  return settings.backend == SCREEN_CAPTURE_WAYLAND;
710 }
711 
712 std::string ScreenCaptureReader::InputFormatName() const
713 {
714  const auto override_format = settings.options.find("input_format_name");
715  if (override_format != settings.options.end()) {
716  return override_format->second;
717  }
718  if (settings.backend == SCREEN_CAPTURE_X11) {
719  return "x11grab";
720  }
721  if (settings.backend == SCREEN_CAPTURE_WINDOWS_GDI) {
722  return "gdigrab";
723  }
724  if (settings.backend == SCREEN_CAPTURE_MAC_AVFOUNDATION) {
725  return "avfoundation";
726  }
727  return "";
728 }
729 
730 std::string ScreenCaptureReader::InputName() const
731 {
732  if (InputFormatName() == "v4l2") {
733  return settings.display.empty() ? "/dev/video0" : settings.display;
734  }
735  if (InputFormatName() == "dshow") {
736  return settings.display;
737  }
738  if (InputFormatName() == "gdigrab") {
739  return settings.display.empty() ? "desktop" : settings.display;
740  }
741  if (InputFormatName() == "avfoundation") {
742  return settings.display.empty() ? "Capture screen 0:none" : settings.display;
743  }
744 
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";
749  }
750  if (InputFormatName() == "x11grab" && settings.options.count("window_id")) {
751  return display;
752  }
753 
754  std::stringstream input;
755  input << display << "+" << settings.x << "," << settings.y;
756  return input.str();
757 }
758 
759 void ScreenCaptureReader::PopulateInfo()
760 {
761  info.has_video = true;
762  info.has_audio = settings.capture_audio;
763  info.has_single_image = false;
764  info.duration = 60.0f * 60.0f;
765  info.file_size = 0;
766  info.width = settings.width;
767  info.height = settings.height;
768  info.pixel_format = AV_PIX_FMT_RGBA;
769  info.fps = settings.fps;
770  info.video_bit_rate = 0;
771  info.pixel_ratio = Fraction(1, 1);
772  info.display_ratio = Fraction(settings.width, settings.height);
774  info.vcodec = "rawvideo";
775  info.video_length = static_cast<int64_t>(info.duration * settings.fps.ToFloat());
777  info.video_timebase = settings.fps.Reciprocal();
778  info.interlaced_frame = false;
779  info.top_field_first = false;
780  info.acodec = settings.capture_audio ? "pcm_f32le" : "";
781  info.audio_bit_rate = 0;
782  info.sample_rate = settings.capture_audio ? settings.audio_sample_rate : 0;
783  info.channels = settings.capture_audio ? settings.audio_channels : 0;
786  info.audio_timebase = Fraction(1, 1);
787 }
788 
790 {
791  if (backend_reader) {
792  if (backend_reader->IsOpen()) return;
793  manual_system_audio = false;
794  if (system_audio) {
795  system_audio->Open();
796  info.sample_rate = system_audio->SampleRate();
797  info.channels = system_audio->Channels();
799  }
800  try {
801  backend_reader->Open();
802  } catch (...) {
803  if (system_audio) system_audio->Close();
804  throw;
805  }
806  return;
807  }
808  if (is_open) {
809  return;
810  }
811  manual_system_audio = false;
812  if (system_audio) {
813  system_audio->Open();
814  info.sample_rate = system_audio->SampleRate();
815  info.channels = system_audio->Channels();
817  }
818  close_requested = false;
819  try {
820  OpenDevice();
821  OpenDecoder();
822  } catch (...) {
823  if (system_audio) system_audio->Close();
824  throw;
825  }
826  is_open = true;
827 }
828 
829 void ScreenCaptureReader::OpenDevice()
830 {
831  avdevice_register_all();
832 
833  AVInputFormat* input_format = const_cast<AVInputFormat*>(av_find_input_format(InputFormatName().c_str()));
834  std::string input_name = InputName();
835  if (!input_format) {
836  throw InvalidOptions("FFmpeg input device is not available: " + InputFormatName(), input_name);
837  }
838 
839  format_context = avformat_alloc_context();
840  if (!format_context) {
841  throw OutOfMemory("Unable to allocate capture format context.", input_name);
842  }
843  format_context->interrupt_callback.callback = capture_interrupt_callback;
844  format_context->interrupt_callback.opaque = &close_requested;
845 
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));
857  }
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);
872  }
873  }
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") {
880  continue;
881  }
882  set_option(&options, option.first, option.second);
883  }
884 
885  const int result = avformat_open_input(&format_context, input_name.c_str(), input_format, &options);
886  av_dict_free(&options);
887  if (result < 0) {
888  throw InvalidFile("Unable to open screen capture input: " + std::string(av_err2str(result)), input_name);
889  }
890 }
891 
892 void ScreenCaptureReader::OpenDecoder()
893 {
894  if (avformat_find_stream_info(format_context, nullptr) < 0) {
895  throw InvalidFile("Unable to read capture stream information.", InputName());
896  }
897 
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);
901  break;
902  }
903  }
904  if (video_stream < 0) {
905  throw InvalidFile("No video stream found in capture input.", InputName());
906  }
907 
908  AVStream* stream = format_context->streams[video_stream];
909  const AVCodec* codec = avcodec_find_decoder(stream->codecpar->codec_id);
910  if (!codec) {
911  throw InvalidCodec("No decoder available for capture stream.", InputName());
912  }
913 
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());
917  }
918 
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")) {
922  info.width = settings.width;
923  info.height = settings.height;
924  }
925  info.video_stream_index = video_stream;
926  info.pixel_format = codec_context->pix_fmt;
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);
938  }
939 
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());
945  }
946 }
947 
948 std::shared_ptr<Frame> ScreenCaptureReader::GetFrame(int64_t number)
949 {
950  if (backend_reader) {
951  if (!backend_reader->IsOpen()) {
952  throw ReaderClosed("The ScreenCaptureReader is closed. Call Open() before GetFrame().");
953  }
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);
957  return frame;
958  }
959  if (!is_open) {
960  throw ReaderClosed("The ScreenCaptureReader is closed. Call Open() before GetFrame().");
961  }
962 
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);
966  return frame;
967 }
968 
969 void ScreenCaptureReader::AddSystemAudio(std::shared_ptr<Frame> frame, int64_t output_frame_number)
970 {
971  if (system_audio) {
972  system_audio->AddFrameAudio(frame, output_frame_number, info.fps);
973  }
974 }
975 
977 {
978  manual_system_audio = true;
979  if (system_audio) {
980  system_audio->Reset();
981  }
982 }
983 
984 std::shared_ptr<Frame> ScreenCaptureReader::DecodeNextFrame(int64_t number)
985 {
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));
990  continue;
991  }
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: ";
996  throw InvalidFile(message + std::string(av_err2str(read_result)), InputName());
997  }
998 
999  if (packet->stream_index != video_stream) {
1000  av_packet_unref(packet);
1001  dropped_packets++;
1002  continue;
1003  }
1004 
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) {
1009  continue;
1010  }
1011 
1012  const int receive_result = avcodec_receive_frame(codec_context, source_frame);
1013  if (receive_result == AVERROR(EAGAIN)) {
1014  continue;
1015  }
1016  if (receive_result < 0) {
1017  throw InvalidFile("Unable to decode capture frame: " + std::string(av_err2str(receive_result)), InputName());
1018  }
1019 
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;
1024  }
1025  if (frame_timestamp == AV_NOPTS_VALUE) {
1026  frame_timestamp = packet_timestamp;
1027  }
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);
1031  }
1032 
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;
1035  const PixelFormat src_fmt = static_cast<PixelFormat>(source_frame->format);
1036 
1037  sws_context = sws_getCachedContext(
1038  sws_context,
1039  width,
1040  height,
1041  src_fmt,
1042  width,
1043  height,
1044  AV_PIX_FMT_RGBA,
1045  SWS_BILINEAR,
1046  nullptr,
1047  nullptr,
1048  nullptr);
1049  if (!sws_context) {
1050  throw InvalidFile("Unable to create capture pixel conversion context.", InputName());
1051  }
1052 
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));
1056  if (!buffer) {
1057  throw OutOfMemory("Unable to allocate capture frame buffer.", InputName());
1058  }
1059 
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);
1063 
1064  if (scaled_lines <= 0) {
1065  openshot::aligned_free(buffer);
1066  continue;
1067  }
1068 
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) {
1080  openshot::aligned_free(buffer);
1081  throw OutOfMemory("Unable to allocate cropped capture frame buffer.", InputName());
1082  }
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);
1088  }
1089  openshot::aligned_free(buffer);
1090  }
1091 
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);
1095  frames_read++;
1096  return frame;
1097  }
1098 
1099  throw ReaderClosed("The ScreenCaptureReader was closed.");
1100 }
1101 
1103 {
1104  close_requested = true;
1105  if (system_audio) {
1106  system_audio->Close();
1107  }
1108  if (backend_reader) {
1109  backend_reader->Close();
1110  }
1111  if (packet) {
1112  av_packet_free(&packet);
1113  }
1114  if (source_frame) {
1115  av_frame_free(&source_frame);
1116  }
1117  if (rgba_frame) {
1118  av_frame_free(&rgba_frame);
1119  }
1120  if (sws_context) {
1121  sws_freeContext(sws_context);
1122  sws_context = nullptr;
1123  }
1124  if (codec_context) {
1125  avcodec_free_context(&codec_context);
1126  }
1127  if (format_context) {
1128  avformat_close_input(&format_context);
1129  }
1130  is_open = false;
1131  video_stream = -1;
1132 }
1133 
1135 {
1136  if (backend_reader) {
1137  return backend_reader->GetStats();
1138  }
1139  CaptureReaderStats stats;
1140  stats.is_open = is_open;
1141  stats.frames_read = frames_read;
1142  stats.dropped_packets = dropped_packets;
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;
1145  return stats;
1146 }
1147 
1148 std::string ScreenCaptureReader::Json() const
1149 {
1150  return JsonValue().toStyledString();
1151 }
1152 
1154 {
1155  Json::Value root = ReaderBase::JsonValue();
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;
1165  root["include_cursor"] = settings.include_cursor;
1166  root["show_region"] = settings.show_region;
1167  root["capture_audio"] = settings.capture_audio;
1168  root["audio_device"] = settings.audio_device;
1169  root["audio_sample_rate"] = settings.audio_sample_rate;
1170  root["audio_channels"] = settings.audio_channels;
1171  root["options"] = Json::Value(Json::objectValue);
1172  for (const auto& option : settings.options) {
1173  root["options"][option.first] = option.second;
1174  }
1175  return root;
1176 }
1177 
1178 void ScreenCaptureReader::SetJson(const std::string value)
1179 {
1180  try {
1182  } catch (const std::exception&) {
1183  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
1184  }
1185 }
1186 
1187 void ScreenCaptureReader::SetJsonValue(const Json::Value root)
1188 {
1189  if (!root["backend"].isNull())
1190  settings.backend = static_cast<ScreenCaptureBackend>(root["backend"].asInt());
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();
1206  }
1207  if (!root["include_cursor"].isNull())
1208  settings.include_cursor = root["include_cursor"].asBool();
1209  if (!root["show_region"].isNull())
1210  settings.show_region = root["show_region"].asBool();
1211  if (!root["capture_audio"].isNull())
1212  settings.capture_audio = root["capture_audio"].asBool();
1213  if (!root["audio_device"].isNull())
1214  settings.audio_device = root["audio_device"].asString();
1215  if (!root["audio_sample_rate"].isNull())
1216  settings.audio_sample_rate = root["audio_sample_rate"].asInt();
1217  if (!root["audio_channels"].isNull())
1218  settings.audio_channels = root["audio_channels"].asInt();
1219  if (!root["options"].isNull() && root["options"].isObject()) {
1220  settings.options.clear();
1221  for (const auto& key : root["options"].getMemberNames()) {
1222  settings.options[key] = root["options"][key].asString();
1223  }
1224  }
1225  if (settings.backend == SCREEN_CAPTURE_AUTO) {
1226  settings.backend = DefaultBackend();
1227  }
1228  ValidateSettings();
1229  PopulateInfo();
1230 #if defined(__linux__) || defined(_WIN32)
1231  system_audio.reset();
1232  if (settings.capture_audio) {
1233  system_audio = std::make_unique<SystemAudioCapture>(settings);
1234  }
1235 #endif
1236 }
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
openshot::ReaderInfo::sample_rate
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:60
openshot::Fraction::ToFloat
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:35
openshot::InvalidSampleRate
Exception when invalid sample rate is detected during encoding.
Definition: Exceptions.h:253
openshot::ScreenCaptureReader::SystemAudioCapture
Definition: ScreenCaptureReader.cpp:451
openshot::ReaderBase::JsonValue
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition: ReaderBase.cpp:110
openshot::ScreenCaptureReader::ScreenCaptureReader
ScreenCaptureReader(const ScreenCaptureSettings &settings)
Definition: ScreenCaptureReader.cpp:569
openshot::InvalidCodec
Exception when no valid codec is found for a file.
Definition: Exceptions.h:178
openshot::ScreenCaptureSettings::include_cursor
bool include_cursor
Definition: ScreenCaptureReader.h:45
openshot::ScreenCaptureReader::SetJson
void SetJson(const std::string value) override
Load JSON string into this object.
Definition: ScreenCaptureReader.cpp:1178
openshot::ScreenCaptureSettings::y
int y
Definition: ScreenCaptureReader.h:41
PixelFormat
#define PixelFormat
Definition: FFmpegUtilities.h:107
openshot::ScreenCaptureSettings::display
std::string display
Definition: ScreenCaptureReader.h:39
openshot::ScreenCaptureReader::ResetSystemAudio
void ResetSystemAudio()
Definition: ScreenCaptureReader.cpp:976
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: AnimatedCurve.h:24
openshot::CaptureReaderStats
Definition: ScreenCaptureReader.h:54
openshot::Fraction
This class represents a fraction.
Definition: Fraction.h:30
openshot::ReaderBase::info
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:91
openshot::SCREEN_CAPTURE_AUTO
@ SCREEN_CAPTURE_AUTO
Definition: ScreenCaptureReader.h:29
openshot::ScreenCaptureReader::IsOpen
bool IsOpen() override
Determine if reader is open or closed.
Definition: ScreenCaptureReader.cpp:612
openshot::ReaderInfo::interlaced_frame
bool interlaced_frame
Definition: ReaderBase.h:56
openshot::ScreenCaptureSettings
Definition: ScreenCaptureReader.h:36
openshot::ScreenCaptureSettings::fps
openshot::Fraction fps
Definition: ScreenCaptureReader.h:44
openshot::ReaderInfo::audio_bit_rate
int audio_bit_rate
The bit rate of the audio stream (in bytes)
Definition: ReaderBase.h:59
openshot::ScreenCaptureReader::Json
std::string Json() const override
Generate JSON string of this object.
Definition: ScreenCaptureReader.cpp:1148
openshot::SCREEN_CAPTURE_MAC_AVFOUNDATION
@ SCREEN_CAPTURE_MAC_AVFOUNDATION
Definition: ScreenCaptureReader.h:33
openshot::ReaderInfo::duration
float duration
Length of time (in seconds)
Definition: ReaderBase.h:43
av_err2str
#define av_err2str(errnum)
Definition: FFmpegUtilities.h:103
QtUtilities.h
Header file for QtUtilities (compatibiity overlay)
openshot::ReaderInfo::has_video
bool has_video
Determines if this file has a video stream.
Definition: ReaderBase.h:40
openshot::ReaderInfo::width
int width
The width of the video (in pixesl)
Definition: ReaderBase.h:46
openshot::LAYOUT_STEREO
@ LAYOUT_STEREO
Definition: ChannelLayouts.h:31
openshot::SCREEN_CAPTURE_WAYLAND
@ SCREEN_CAPTURE_WAYLAND
Definition: ScreenCaptureReader.h:31
openshot::ScreenCaptureReader::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t number) override
Definition: ScreenCaptureReader.cpp:948
openshot::ScreenCaptureReader::~ScreenCaptureReader
~ScreenCaptureReader() override
Definition: ScreenCaptureReader.cpp:607
openshot::ScreenCaptureReader::SystemAudioCapture::Channels
int Channels() const
Definition: ScreenCaptureReader.cpp:460
openshot::ScreenCaptureReader::IsSystemAudioSupported
static bool IsSystemAudioSupported(ScreenCaptureBackend backend)
Definition: ScreenCaptureReader.cpp:639
openshot::LAYOUT_MONO
@ LAYOUT_MONO
Definition: ChannelLayouts.h:30
openshot::aligned_free
void aligned_free(void *ptr)
Definition: QtUtilities.h:32
openshot::ReaderInfo::video_length
int64_t video_length
The number of frames in the video stream.
Definition: ReaderBase.h:53
openshot::ReaderInfo::height
int height
The height of the video (in pixels)
Definition: ReaderBase.h:45
openshot::Fraction::num
int num
Numerator for the fraction.
Definition: Fraction.h:32
if
if(!codec) codec
openshot::Fraction::den
int den
Denominator for the fraction.
Definition: Fraction.h:33
openshot::ScreenCaptureReader::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition: ScreenCaptureReader.cpp:1153
openshot::Fraction::Reduce
void Reduce()
Reduce this fraction (i.e. 640/480 = 4/3)
Definition: Fraction.cpp:65
openshot::Fraction::Reciprocal
Fraction Reciprocal() const
Return the reciprocal as a Fraction.
Definition: Fraction.cpp:78
openshot::ReaderInfo::has_audio
bool has_audio
Determines if this file has an audio stream.
Definition: ReaderBase.h:41
openshot::ScreenCaptureReader::DefaultBackend
static ScreenCaptureBackend DefaultBackend()
Definition: ScreenCaptureReader.cpp:656
openshot::ScreenCaptureSettings::backend
ScreenCaptureBackend backend
Definition: ScreenCaptureReader.h:38
openshot::InvalidJSON
Exception for invalid JSON.
Definition: Exceptions.h:223
openshot::ReaderInfo::file_size
int64_t file_size
Size of file (in bytes)
Definition: ReaderBase.h:44
openshot::CaptureReaderStats::dropped_packets
int dropped_packets
Definition: ScreenCaptureReader.h:58
openshot::CaptureReaderStats::is_open
bool is_open
Definition: ScreenCaptureReader.h:56
openshot::OutOfMemory
Exception when memory could not be allocated.
Definition: Exceptions.h:354
ScreenCaptureReader.h
Header file for live screen capture readers.
openshot::ScreenCaptureSettings::show_region
bool show_region
Definition: ScreenCaptureReader.h:46
openshot::ReaderInfo
This struct contains info about a media file, such as height, width, frames per second,...
Definition: ReaderBase.h:38
openshot::ReaderInfo::has_single_image
bool has_single_image
Determines if this file only contains a single image.
Definition: ReaderBase.h:42
openshot::ReaderInfo::video_timebase
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition: ReaderBase.h:55
openshot::ScreenCaptureSettings::height
int height
Definition: ScreenCaptureReader.h:43
openshot::ScreenCaptureReader::SystemAudioCapture::AddFrameAudio
void AddFrameAudio(const std::shared_ptr< Frame > &, int64_t, const Fraction &)
Definition: ScreenCaptureReader.cpp:457
openshot::SCREEN_CAPTURE_X11
@ SCREEN_CAPTURE_X11
Definition: ScreenCaptureReader.h:30
Frame.h
Header file for Frame class.
openshot::Frame::GetSamplesPerFrame
int GetSamplesPerFrame(openshot::Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Definition: Frame.cpp:486
openshot::ScreenCaptureBackend
ScreenCaptureBackend
Definition: ScreenCaptureReader.h:27
HAVE_CH_LAYOUT
#define HAVE_CH_LAYOUT
Definition: FFmpegUtilities.h:36
openshot::InvalidFile
Exception for files that can not be found or opened.
Definition: Exceptions.h:193
openshot::ReaderInfo::audio_stream_index
int audio_stream_index
The index of the audio stream.
Definition: ReaderBase.h:63
openshot::ReaderInfo::audio_timebase
openshot::Fraction audio_timebase
The audio timebase determines how long each audio packet should be played.
Definition: ReaderBase.h:64
openshot::ReaderInfo::pixel_format
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
Definition: ReaderBase.h:47
openshot::ReaderInfo::vcodec
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: ReaderBase.h:52
CreateWaylandScreenCaptureReader
std::unique_ptr< ScreenCaptureReader::CaptureBackendReader > CreateWaylandScreenCaptureReader(const ScreenCaptureSettings &settings, ReaderInfo &info)
Definition: WaylandScreenCaptureReader.cpp:923
openshot::ScreenCaptureReader::SystemAudioCapture::SampleRate
int SampleRate() const
Definition: ScreenCaptureReader.cpp:459
openshot::ScreenCaptureSettings::options
std::map< std::string, std::string > options
Definition: ScreenCaptureReader.h:51
openshot::ReaderClosed
Exception when a reader is closed, and a frame is requested.
Definition: Exceptions.h:369
openshot::ScreenCaptureReader::GetStats
openshot::CaptureReaderStats GetStats() const
Definition: ScreenCaptureReader.cpp:1134
openshot::ReaderInfo::channel_layout
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
Definition: ReaderBase.h:62
openshot::ScreenCaptureReader::SystemAudioCapture::Close
void Close()
Definition: ScreenCaptureReader.cpp:456
openshot::ScreenCaptureSettings::audio_device
std::string audio_device
Definition: ScreenCaptureReader.h:48
openshot::CaptureReaderStats::frames_read
int64_t frames_read
Definition: ScreenCaptureReader.h:57
openshot::ScreenCaptureSettings::x
int x
Definition: ScreenCaptureReader.h:40
openshot::ReaderInfo::fps
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: ReaderBase.h:48
openshot::ScreenCaptureReader::IsBackendSupported
static bool IsBackendSupported(ScreenCaptureBackend backend)
Definition: ScreenCaptureReader.cpp:617
openshot::ReaderInfo::video_bit_rate
int video_bit_rate
The bit rate of the video stream (in bytes)
Definition: ReaderBase.h:49
openshot::ScreenCaptureSettings::audio_sample_rate
int audio_sample_rate
Definition: ScreenCaptureReader.h:49
openshot::ReaderInfo::top_field_first
bool top_field_first
Definition: ReaderBase.h:57
openshot::InvalidChannels
Exception when an invalid # of audio channels are detected.
Definition: Exceptions.h:163
openshot::ScreenCaptureSettings::width
int width
Definition: ScreenCaptureReader.h:42
openshot::ScreenCaptureSettings::audio_channels
int audio_channels
Definition: ScreenCaptureReader.h:50
codec
codec
Definition: FFmpegWriter.cpp:1574
openshot::ScreenCaptureSettings::capture_audio
bool capture_audio
Definition: ScreenCaptureReader.h:47
openshot::ReaderInfo::pixel_ratio
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square)
Definition: ReaderBase.h:50
openshot::ScreenCaptureReader::SystemAudioCapture::SystemAudioCapture
SystemAudioCapture(const ScreenCaptureSettings &)
Definition: ScreenCaptureReader.cpp:454
openshot::ScreenCaptureReader::Open
void Open() override
Open the reader (and start consuming resources, such as images or video files)
Definition: ScreenCaptureReader.cpp:789
openshot::ScreenCaptureReader::SetJsonValue
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition: ScreenCaptureReader.cpp:1187
openshot::ScreenCaptureReader::SystemAudioCapture::Reset
void Reset()
Definition: ScreenCaptureReader.cpp:458
openshot::ScreenCaptureReader::AddSystemAudio
void AddSystemAudio(std::shared_ptr< openshot::Frame > frame, int64_t output_frame_number)
Definition: ScreenCaptureReader.cpp:969
openshot::ReaderInfo::video_stream_index
int video_stream_index
The index of the video stream.
Definition: ReaderBase.h:54
openshot::InvalidOptions
Exception when invalid encoding options are used.
Definition: Exceptions.h:238
openshot::ReaderInfo::acodec
std::string acodec
The name of the audio codec used to encode / decode the video stream.
Definition: ReaderBase.h:58
openshot::SCREEN_CAPTURE_WINDOWS_GDI
@ SCREEN_CAPTURE_WINDOWS_GDI
Definition: ScreenCaptureReader.h:32
openshot::ReaderInfo::display_ratio
openshot::Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3)
Definition: ReaderBase.h:51
openshot::ReaderInfo::channels
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:61
openshot::ScreenCaptureReader::Close
void Close() override
Close the reader (and any resources it was consuming)
Definition: ScreenCaptureReader.cpp:1102
openshot::ScreenCaptureReader::SystemAudioCapture::Open
void Open()
Definition: ScreenCaptureReader.cpp:455
openshot::CaptureReaderStats::duration
double duration
Definition: ScreenCaptureReader.h:59
Exceptions.h
Header file for all Exception classes.
openshot::ReaderBase::getFrameMutex
std::recursive_mutex getFrameMutex
Mutex for multiple threads.
Definition: ReaderBase.h:79