diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index dbb4454af000..73d83bd142d6 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -10,6 +10,7 @@ import("//extensions/buildflags/buildflags.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//pdf/features.gni")
 import("//rlz/buildflags/buildflags.gni")
+import("//third_party/webrtc/webrtc.gni")
 
 assert(enable_extensions)
 
@@ -1213,4 +1214,9 @@ static_library("extensions") {
   } else {
     sources += [ "api/braille_display_private/braille_controller_stub.cc" ]
   }
+
+  if (rtc_use_pipewire) {
+    configs +=
+        [ "//third_party/webrtc/modules/desktop_capture:pipewire_config" ]
+  }
 }
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
index fa790782b3ee..931e0d4efb22 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
@@ -32,6 +32,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "url/origin.h"
 
+#if defined(WEBRTC_USE_PIPEWIRE)
+#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
+#endif
+
 using content::DesktopMediaID;
 using extensions::api::desktop_capture::ChooseDesktopMedia::Results::Options;
 
@@ -167,6 +171,18 @@ void DesktopCaptureChooseDesktopMediaFunctionBase::OnPickerDialogResults(
 
   std::string result;
   if (source.type != DesktopMediaID::TYPE_NONE && web_contents) {
+#if defined(WEBRTC_USE_PIPEWIRE)
+    // Abuse Id and use it as our identificator
+    if (content::desktop_capture::CanUsePipeWire()) {
+      if (source.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) {
+        content::desktop_capture::CreateDesktopCaptureOptionsPipeWire()
+            .xdp_base()
+            ->CloseConnection(web_contents->GetSiteInstance()->GetId());
+      } else {
+        source.id = web_contents->GetSiteInstance()->GetId();
+      }
+    }
+#endif
     // TODO(miu): Once render_frame_host() is being set, we should register the
     // exact RenderFrame requesting the stream, not the main RenderFrame.  With
     // that change, also update
@@ -178,7 +194,15 @@ void DesktopCaptureChooseDesktopMediaFunctionBase::OnPickerDialogResults(
         url::Origin::Create(origin), source, extension()->name(),
         content::kRegistryStreamTypeDesktop);
   }
-
+#if defined(WEBRTC_USE_PIPEWIRE)
+  else {
+    if (content::desktop_capture::CanUsePipeWire()) {
+      content::desktop_capture::CreateDesktopCaptureOptionsPipeWire()
+          .xdp_base()
+          ->CloseConnection(web_contents->GetSiteInstance()->GetId());
+    }
+  }
+#endif
   Options options;
   options.can_request_audio_track = source.audio_share;
   Respond(ArgumentList(Create(result, options)));
diff --git a/chrome/browser/media/webrtc/desktop_media_picker_controller.cc b/chrome/browser/media/webrtc/desktop_media_picker_controller.cc
index 74462a827a7e..4e6bfb91357e 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker_controller.cc
+++ b/chrome/browser/media/webrtc/desktop_media_picker_controller.cc
@@ -53,7 +53,14 @@ void DesktopMediaPickerController::Show(
   Observe(params.web_contents);
 
   // Keep same order as the input |sources| and avoid duplicates.
-  source_lists_ = picker_factory_->CreateMediaList(sources);
+#if defined(WEBRTC_USE_PIPEWIRE)
+  if (content::desktop_capture::CanUsePipeWire()) {
+    source_lists_ = picker_factory_->CreateMediaListPipeWire(
+        sources, params.web_contents->GetSiteInstance()->GetId());
+  } else
+#endif
+    source_lists_ = picker_factory_->CreateMediaList(sources);
+
   if (source_lists_.empty()) {
     OnPickerDialogResults("At least one source type must be specified.", {});
     return;
diff --git a/chrome/browser/media/webrtc/desktop_media_picker_factory.h b/chrome/browser/media/webrtc/desktop_media_picker_factory.h
index 0e393e91a4d1..bdc149ec19fe 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker_factory.h
+++ b/chrome/browser/media/webrtc/desktop_media_picker_factory.h
@@ -22,7 +22,12 @@ class DesktopMediaPickerFactory {
   virtual std::unique_ptr<DesktopMediaPicker> CreatePicker() = 0;
   virtual std::vector<std::unique_ptr<DesktopMediaList>> CreateMediaList(
       const std::vector<content::DesktopMediaID::Type>& types) = 0;
-
+#if defined(WEBRTC_USE_PIPEWIRE)
+  virtual std::vector<std::unique_ptr<DesktopMediaList>>
+  CreateMediaListPipeWire(
+      const std::vector<content::DesktopMediaID::Type>& types,
+      int32_t id) = 0;
+#endif
  protected:
   DesktopMediaPickerFactory();
 
diff --git a/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.cc b/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.cc
index fa7d872810a6..34d79a93aa64 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.cc
+++ b/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.cc
@@ -89,3 +89,56 @@ DesktopMediaPickerFactoryImpl::CreateMediaList(
   }
   return source_lists;
 }
+
+#if defined(WEBRTC_USE_PIPEWIRE)
+std::vector<std::unique_ptr<DesktopMediaList>>
+DesktopMediaPickerFactoryImpl::CreateMediaListPipeWire(
+    const std::vector<content::DesktopMediaID::Type>& types,
+    int32_t id) {
+  // Keep same order as the input |sources| and avoid duplicates.
+  std::vector<std::unique_ptr<DesktopMediaList>> source_lists;
+  bool have_screen_list = false;
+  bool have_window_list = false;
+  bool have_tab_list = false;
+  for (auto source_type : types) {
+    switch (source_type) {
+      case content::DesktopMediaID::TYPE_NONE:
+        break;
+      case content::DesktopMediaID::TYPE_SCREEN: {
+        if (have_screen_list)
+          continue;
+        std::unique_ptr<DesktopMediaList> screen_list;
+        screen_list = std::make_unique<NativeDesktopMediaList>(
+            content::DesktopMediaID::TYPE_SCREEN,
+            content::desktop_capture::CreatePipeWireCapturer(
+                id, content::DesktopMediaID::TYPE_SCREEN, false));
+        have_screen_list = true;
+        source_lists.push_back(std::move(screen_list));
+        break;
+      }
+      case content::DesktopMediaID::TYPE_WINDOW: {
+        if (have_window_list)
+          continue;
+        std::unique_ptr<DesktopMediaList> window_list;
+        window_list = std::make_unique<NativeDesktopMediaList>(
+            content::DesktopMediaID::TYPE_WINDOW,
+            content::desktop_capture::CreatePipeWireCapturer(
+                id, content::DesktopMediaID::TYPE_WINDOW, false));
+        have_window_list = true;
+        source_lists.push_back(std::move(window_list));
+        break;
+      }
+      case content::DesktopMediaID::TYPE_WEB_CONTENTS: {
+        if (have_tab_list)
+          continue;
+        std::unique_ptr<DesktopMediaList> tab_list =
+            std::make_unique<TabDesktopMediaList>();
+        have_tab_list = true;
+        source_lists.push_back(std::move(tab_list));
+        break;
+      }
+    }
+  }
+  return source_lists;
+}
+#endif
diff --git a/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.h b/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.h
index 4888b591445b..d8fd3dcbb5d1 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.h
+++ b/chrome/browser/media/webrtc/desktop_media_picker_factory_impl.h
@@ -27,6 +27,11 @@ class DesktopMediaPickerFactoryImpl : public DesktopMediaPickerFactory {
   std::unique_ptr<DesktopMediaPicker> CreatePicker() override;
   std::vector<std::unique_ptr<DesktopMediaList>> CreateMediaList(
       const std::vector<content::DesktopMediaID::Type>& types) override;
+#if defined(WEBRTC_USE_PIPEWIRE)
+  std::vector<std::unique_ptr<DesktopMediaList>> CreateMediaListPipeWire(
+      const std::vector<content::DesktopMediaID::Type>& types,
+      int32_t id) override;
+#endif
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerFactoryImpl);
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.cc b/chrome/browser/media/webrtc/display_media_access_handler.cc
index a5d00899b1df..0a645704a699 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/display_media_access_handler.cc
@@ -29,6 +29,10 @@
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
 
+#if defined(WEBRTC_USE_PIPEWIRE)
+#include "third_party/webrtc/modules/desktop_capture/linux/xdg_desktop_portal_base.h"
+#endif
+
 #if defined(OS_MACOSX)
 #include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
 #endif
@@ -168,7 +172,15 @@ void DisplayMediaAccessHandler::ProcessQueuedAccessRequest(
       content::DesktopMediaID::TYPE_SCREEN,
       content::DesktopMediaID::TYPE_WINDOW,
       content::DesktopMediaID::TYPE_WEB_CONTENTS};
-  auto source_lists = picker_factory_->CreateMediaList(media_types);
+
+  std::vector<std::unique_ptr<DesktopMediaList>> source_lists;
+#if defined(WEBRTC_USE_PIPEWIRE)
+  if (content::desktop_capture::CanUsePipeWire()) {
+    source_lists = picker_factory_->CreateMediaListPipeWire(
+        media_types, web_contents->GetSiteInstance()->GetId());
+  } else
+#endif
+    source_lists = picker_factory_->CreateMediaList(media_types);
 
   DesktopMediaPicker::DoneCallback done_callback =
       base::BindOnce(&DisplayMediaAccessHandler::OnPickerDialogResults,
@@ -211,9 +223,29 @@ void DisplayMediaAccessHandler::OnPickerDialogResults(
   blink::mojom::MediaStreamRequestResult request_result =
       blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
   std::unique_ptr<content::MediaStreamUI> ui;
+
   if (media_id.is_null()) {
     request_result = blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
+#if defined(WEBRTC_USE_PIPEWIRE)
+    if (content::desktop_capture::CanUsePipeWire()) {
+      content::desktop_capture::CreateDesktopCaptureOptionsPipeWire()
+          .xdp_base()
+          ->CloseConnection(web_contents->GetSiteInstance()->GetId());
+    }
+#endif
   } else {
+#if defined(WEBRTC_USE_PIPEWIRE)
+    // Abuse Id and use it as our identificator
+    if (content::desktop_capture::CanUsePipeWire()) {
+      if (media_id.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) {
+        content::desktop_capture::CreateDesktopCaptureOptionsPipeWire()
+            .xdp_base()
+            ->CloseConnection(web_contents->GetSiteInstance()->GetId());
+      } else {
+        media_id.id = web_contents->GetSiteInstance()->GetId();
+      }
+    }
+#endif
     request_result = blink::mojom::MediaStreamRequestResult::OK;
 #if defined(OS_MACOSX)
     // Check screen capture permissions on Mac if necessary.
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.h b/chrome/browser/media/webrtc/display_media_access_handler.h
index 8ae226f23240..843f53d412dd 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.h
+++ b/chrome/browser/media/webrtc/display_media_access_handler.h
@@ -19,6 +19,10 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
+#if defined(WEBRTC_USE_PIPEWIRE)
+#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
+#endif
+
 namespace extensions {
 class Extension;
 }
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
index c81645e60a2a..2ea9bf6cd371 100644
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
@@ -18,6 +18,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/desktop_capture.h"
 #include "media/base/video_util.h"
 #include "third_party/libyuv/include/libyuv/scale_argb.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -168,8 +169,11 @@ void NativeDesktopMediaList::Worker::Refresh(
 
       case DesktopMediaID::TYPE_WINDOW:
         // Skip the picker dialog window.
-        if (sources[i].id == view_dialog_id)
-          continue;
+#if defined(WEBRTC_USE_PIPEWIRE)
+        if (!content::desktop_capture::CanUsePipeWire())
+#endif
+          if (sources[i].id == view_dialog_id)
+            continue;
         title = base::UTF8ToUTF16(sources[i].title);
         break;
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 612d7a2b93c6..a6eecb08c9b7 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -23,6 +23,7 @@ import("//ppapi/buildflags/buildflags.gni")
 import("//printing/buildflags/buildflags.gni")
 import("//rlz/buildflags/buildflags.gni")
 import("//third_party/protobuf/proto_library.gni")
+import("//third_party/webrtc/webrtc.gni")
 import("//ui/base/ui_features.gni")
 import("//ui/views/features.gni")
 
@@ -3555,6 +3556,11 @@ static_library("ui") {
       "//ui/views:buildflags",
     ]
 
+    if (rtc_use_pipewire) {
+      configs +=
+          [ "//third_party/webrtc/modules/desktop_capture:pipewire_config" ]
+    }
+
     allow_circular_includes_from += [ "//chrome/browser/ui/views" ]
 
     if (is_desktop_linux) {
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index afab8aa7b384..20e47787666d 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -24,6 +24,7 @@
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/desktop_capture.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -35,7 +36,6 @@
 #include "ui/views/controls/tabbed_pane/tabbed_pane.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/widget/widget.h"
-
 #if defined(USE_AURA)
 #include "ui/aura/window_tree_host.h"
 #endif
@@ -135,6 +135,16 @@ DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
       case DesktopMediaID::TYPE_WINDOW: {
         source_types_.push_back(DesktopMediaID::TYPE_WINDOW);
 
+#if defined(WEBRTC_USE_PIPEWIRE)
+        const DesktopMediaSourceViewStyle kSingleScreenStyle(
+            1,                                       // columns
+            gfx::Size(360, 280),                     // item_size
+            gfx::Rect(),                             // icon_rect
+            gfx::Rect(),                             // label_rect
+            gfx::HorizontalAlignment::ALIGN_CENTER,  // text_alignment
+            gfx::Rect(20, 20, 320, 240),             // image_rect
+            5);                                      // focus_rectangle_inset
+#endif
         const DesktopMediaSourceViewStyle kWindowStyle(
             3,                                     // columns
             gfx::Size(180, 160),                   // item_size
@@ -150,12 +160,25 @@ DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
             IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_WINDOW);
         auto list_controller = std::make_unique<DesktopMediaListController>(
             this, std::move(source_list));
-        window_scroll_view->SetContents(list_controller->CreateView(
-            kWindowStyle, kWindowStyle, window_title_text));
+#if defined(WEBRTC_USE_PIPEWIRE)
+        if (content::desktop_capture::CanUsePipeWire()) {
+          window_scroll_view->SetContents(list_controller->CreateView(
+              kSingleScreenStyle, kSingleScreenStyle, window_title_text));
+        } else
+#endif
+          window_scroll_view->SetContents(list_controller->CreateView(
+              kWindowStyle, kWindowStyle, window_title_text));
         list_controllers_.push_back(std::move(list_controller));
 
-        window_scroll_view->ClipHeightTo(kWindowStyle.item_size.height(),
-                                         kWindowStyle.item_size.height() * 2);
+#if defined(WEBRTC_USE_PIPEWIRE)
+        if (content::desktop_capture::CanUsePipeWire()) {
+          window_scroll_view->ClipHeightTo(
+              kSingleScreenStyle.item_size.height(),
+              kSingleScreenStyle.item_size.height() * 2);
+        } else
+#endif
+          window_scroll_view->ClipHeightTo(kWindowStyle.item_size.height(),
+                                           kWindowStyle.item_size.height() * 2);
         window_scroll_view->SetHideHorizontalScrollBar(true);
 
         panes.push_back(
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 593dd9fe5cf5..969c49ada441 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -17,6 +17,7 @@ import("//net/features.gni")
 import("//ppapi/buildflags/buildflags.gni")
 import("//printing/buildflags/buildflags.gni")
 import("//third_party/blink/public/public_features.gni")
+import("//third_party/webrtc/webrtc.gni")
 import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
 
 jumbo_source_set("browser") {
@@ -2128,6 +2129,11 @@ jumbo_source_set("browser") {
     ]
   }
 
+  if (rtc_use_pipewire) {
+    configs +=
+        [ "//third_party/webrtc/modules/desktop_capture:pipewire_config" ]
+  }
+
   # Desktop/Window/WebContents screen capture implementations, conditionally
   # built depending on the available implementations for each platform.
   if (enable_screen_capture && !is_android) {
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index 3385690f9b97..7b386677270e 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -497,7 +497,14 @@ base::TimeTicks DesktopCaptureDevice::Core::NowTicks() const {
 // static
 std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
     const DesktopMediaID& source) {
+#if defined(WEBRTC_USE_PIPEWIRE)
+  auto options = desktop_capture::CanUsePipeWire()
+                     ? desktop_capture::CreateDesktopCaptureOptionsPipeWire()
+                     : desktop_capture::CreateDesktopCaptureOptions();
+#else
   auto options = desktop_capture::CreateDesktopCaptureOptions();
+#endif
+
   std::unique_ptr<webrtc::DesktopCapturer> capturer;
   std::unique_ptr<media::VideoCaptureDevice> result;
 
@@ -510,6 +517,20 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
 
   switch (source.type) {
     case DesktopMediaID::TYPE_SCREEN: {
+#if defined(WEBRTC_USE_PIPEWIRE)
+      if (desktop_capture::CanUsePipeWire()) {
+        std::unique_ptr<webrtc::DesktopCapturer> portal_capturer =
+            desktop_capture::CreatePipeWireCapturer(source.id,
+                                                    DesktopMediaID::TYPE_NONE);
+        if (portal_capturer && portal_capturer->SelectSource(source.id)) {
+          capturer.reset(new webrtc::DesktopAndCursorComposer(
+              std::move(portal_capturer), options));
+          IncrementDesktopCaptureCounter(SCREEN_CAPTURER_CREATED);
+        }
+        break;
+      }
+#endif
+
       std::unique_ptr<webrtc::DesktopCapturer> screen_capturer(
           webrtc::DesktopCapturer::CreateScreenCapturer(options));
       if (screen_capturer && screen_capturer->SelectSource(source.id)) {
@@ -524,6 +545,19 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
     }
 
     case DesktopMediaID::TYPE_WINDOW: {
+#if defined(WEBRTC_USE_PIPEWIRE)
+      if (desktop_capture::CanUsePipeWire()) {
+        std::unique_ptr<webrtc::DesktopCapturer> portal_capturer =
+            desktop_capture::CreatePipeWireCapturer(source.id,
+                                                    DesktopMediaID::TYPE_NONE);
+        if (portal_capturer && portal_capturer->SelectSource(source.id)) {
+          capturer.reset(new webrtc::DesktopAndCursorComposer(
+              std::move(portal_capturer), options));
+          IncrementDesktopCaptureCounter(WINDOW_CAPTURER_CREATED);
+        }
+        break;
+      }
+#endif
       std::unique_ptr<webrtc::DesktopCapturer> window_capturer =
           webrtc::CroppingWindowCapturer::CreateCapturer(options);
       if (window_capturer && window_capturer->SelectSource(source.id)) {
diff --git a/content/public/browser/desktop_capture.cc b/content/public/browser/desktop_capture.cc
index 95bc55c6ebda..a133aa4ea6c9 100644
--- a/content/public/browser/desktop_capture.cc
+++ b/content/public/browser/desktop_capture.cc
@@ -48,5 +48,48 @@ std::unique_ptr<webrtc::DesktopCapturer> CreateWindowCapturer() {
       CreateDesktopCaptureOptions());
 }
 
+#if defined(WEBRTC_USE_PIPEWIRE)
+std::unique_ptr<webrtc::DesktopCapturer> CreatePipeWireCapturer(
+    int32_t web_id,
+    content::DesktopMediaID::Type type,
+    bool auto_close_connection) {
+  webrtc::DesktopCaptureOptions options =
+      content::desktop_capture::CreateDesktopCaptureOptionsPipeWire();
+
+  webrtc::XdgDesktopPortalBase::CaptureSourceType source_type;
+  switch (type) {
+    case content::DesktopMediaID::TYPE_SCREEN:
+      source_type = webrtc::XdgDesktopPortalBase::CaptureSourceType::kScreen;
+      break;
+    case content::DesktopMediaID::TYPE_WINDOW:
+      source_type = webrtc::XdgDesktopPortalBase::CaptureSourceType::kWindow;
+      break;
+    default:
+      source_type = webrtc::XdgDesktopPortalBase::CaptureSourceType::kAny;
+      break;
+  }
+
+  return webrtc::BaseCapturerPipeWire::CreateRawPipeWireCapturer(
+      options, source_type, web_id, auto_close_connection);
+}
+
+webrtc::DesktopCaptureOptions CreateDesktopCaptureOptionsPipeWire() {
+  static base::NoDestructor<webrtc::DesktopCaptureOptions> options([]() {
+    auto options = webrtc::DesktopCaptureOptions::CreateDefault();
+    // Leave desktop effects enabled during WebRTC captures.
+    options.set_disable_effects(false);
+    options.set_allow_pipewire(true);
+    return options;
+  }());
+  return *options;
+}
+
+bool CanUsePipeWire() {
+  return webrtc::DesktopCapturer::IsRunningUnderWayland() &&
+         base::FeatureList::IsEnabled(features::kWebRtcPipeWireCapturer);
+}
+
+#endif
+
 }  // namespace desktop_capture
 }  // namespace content
diff --git a/content/public/browser/desktop_capture.h b/content/public/browser/desktop_capture.h
index c90997a8762a..fed054b66759 100644
--- a/content/public/browser/desktop_capture.h
+++ b/content/public/browser/desktop_capture.h
@@ -5,9 +5,15 @@
 #ifndef CONTENT_PUBLIC_BROWSER_DESKTOP_CAPTURE_H_
 #define CONTENT_PUBLIC_BROWSER_DESKTOP_CAPTURE_H_
 
+#include "base/no_destructor.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/desktop_media_id.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
+#if defined(WEBRTC_USE_PIPEWIRE)
+#include "third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h"
+#include "third_party/webrtc/modules/desktop_capture/linux/xdg_desktop_portal_base.h"
+#endif
 
 namespace content {
 namespace desktop_capture {
@@ -19,6 +25,16 @@ CONTENT_EXPORT webrtc::DesktopCaptureOptions CreateDesktopCaptureOptions();
 CONTENT_EXPORT std::unique_ptr<webrtc::DesktopCapturer> CreateScreenCapturer();
 CONTENT_EXPORT std::unique_ptr<webrtc::DesktopCapturer> CreateWindowCapturer();
 
+#if defined(WEBRTC_USE_PIPEWIRE)
+CONTENT_EXPORT std::unique_ptr<webrtc::DesktopCapturer> CreatePipeWireCapturer(
+    int32_t web_id,
+    content::DesktopMediaID::Type,
+    bool auto_close_connection = true);
+CONTENT_EXPORT webrtc::DesktopCaptureOptions
+CreateDesktopCaptureOptionsPipeWire();
+CONTENT_EXPORT bool CanUsePipeWire();
+#endif
+
 }  // namespace desktop_capture
 }  // namespace content
 
