WebRTC无法录屏

2023-12-24

我正在尝试使用 WebRTC 制作屏幕共享应用程序。我有可以从相机获取和共享视频流的代码。我需要修改它以通过 MediaProjection API 获取视频。基于此post https://groups.google.com/d/msg/discuss-webrtc/yMrE6I4d_Wc/a3Le89mnAgAJ我已修改代码以使用 org.webrtc.ScreenCapturerAndroid,但没有显示视频输出。只有黑屏。如果我使用相机,一切正常(我可以在屏幕上看到相机输出)。有人可以检查我的代码并指出我正确的方向吗?我已经被这个问题困扰了三天了。

这是我的代码:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "VIDEO_CAPTURE";

    private static final int CAPTURE_PERMISSION_REQUEST_CODE = 1;
    private static final String VIDEO_TRACK_ID = "video_stream";

    PeerConnectionFactory peerConnectionFactory;

    SurfaceViewRenderer localVideoView;
    ProxyVideoSink localSink;

    VideoSource videoSource;
    VideoTrack localVideoTrack;

    EglBase rootEglBase;

    boolean camera = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rootEglBase = EglBase.create();
        localVideoView = findViewById(R.id.local_gl_surface_view);

        localVideoView.init(rootEglBase.getEglBaseContext(), null);

        startScreenCapture();
    }

    @TargetApi(21)
    private void startScreenCapture() {
        MediaProjectionManager mMediaProjectionManager = (MediaProjectionManager) getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), CAPTURE_PERMISSION_REQUEST_CODE);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode != CAPTURE_PERMISSION_REQUEST_CODE) { return; }

        start(data);
    }

    private void start(Intent permissionData) {

        //Initialize PeerConnectionFactory globals.
        PeerConnectionFactory.InitializationOptions initializationOptions =
                PeerConnectionFactory.InitializationOptions.builder(this)
                        .setEnableVideoHwAcceleration(true)
                        .createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);

        //Create a new PeerConnectionFactory instance - using Hardware encoder and decoder.
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(
                rootEglBase.getEglBaseContext(), true,true);
        DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext());

        peerConnectionFactory = PeerConnectionFactory.builder()
                .setOptions(options)
                .setVideoDecoderFactory(defaultVideoDecoderFactory)
                .setVideoEncoderFactory(defaultVideoEncoderFactory)
                .createPeerConnectionFactory();;

        VideoCapturer videoCapturerAndroid;
        if (camera) {
            videoCapturerAndroid = createCameraCapturer(new Camera1Enumerator(false));
        } else {
            videoCapturerAndroid = new ScreenCapturerAndroid(permissionData, new MediaProjection.Callback() {
                @Override
                public void onStop() {
                    super.onStop();
                    Log.e(TAG, "user has revoked permissions");
                }
            });
        }

        videoSource = peerConnectionFactory.createVideoSource(videoCapturerAndroid);

        DisplayMetrics metrics = new DisplayMetrics();
        MainActivity.this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
        videoCapturerAndroid.startCapture(metrics.widthPixels, metrics.heightPixels, 30);

        localVideoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
        localVideoTrack.setEnabled(true);

        //localVideoTrack.addRenderer(new VideoRenderer(localRenderer));
        localSink = new ProxyVideoSink().setTarget(localVideoView);
        localVideoTrack.addSink(localSink);
    }

    //find first camera, this works without problem
    private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
        final String[] deviceNames = enumerator.getDeviceNames();

        // First, try to find front facing camera
        Logging.d(TAG, "Looking for front facing cameras.");
        for (String deviceName : deviceNames) {
            if (enumerator.isFrontFacing(deviceName)) {
                Logging.d(TAG, "Creating front facing camera capturer.");
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        // Front facing camera not found, try something else
        Logging.d(TAG, "Looking for other cameras.");
        for (String deviceName : deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                Logging.d(TAG, "Creating other camera capturer.");
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        return null;
    }
}

代理视频接收器

public class ProxyVideoSink implements VideoSink {

    private VideoSink target;

    synchronized ProxyVideoSink setTarget(VideoSink target) { this.target = target; return this; }

    @Override
    public void onFrame(VideoFrame videoFrame) {

        if (target == null) {
            Log.w("VideoSink", "Dropping frame in proxy because target is null.");
            return;
        }

        target.onFrame(videoFrame);
    }
}

在 logcat 中我可以看到,有些帧已渲染,但没有显示任何内容(黑屏)。

06-18 17:42:44.750 11357-11388/com.archona.webrtcscreencapturetest I/org.webrtc.Logging: EglRenderer: local_gl_surface_viewDuration: 4000 ms. Frames received: 117. Dropped: 0. Rendered: 117. Render fps: 29.2. Average render time: 4754 μs. Average swapBuffer time: 2913 μs.
06-18 17:42:48.752 11357-11388/com.archona.webrtcscreencapturetest I/org.webrtc.Logging: EglRenderer: local_gl_surface_viewDuration: 4001 ms. Frames received: 118. Dropped: 0. Rendered: 118. Render fps: 29.5. Average render time: 5015 μs. Average swapBuffer time: 3090 μs.

我正在使用最新版本的 WebRTC 库:实现“org.webrtc:google-webrtc:1.0.23546”。 我的设备具有 API 级别 24 (Android 7.0),但我已在具有不同 API 级别的 3 个不同设备上测试了此代码,因此我不怀疑设备特定问题。 我尝试构建另一个使用 MediaProjection API(不带 WebRTC)的应用程序,我可以在 SurfaceView 中看到正确的输出。 我尝试过降级 webrtc 库,但似乎没有任何效果。

谢谢你的帮助。


我在使用 WebRTC 库时遇到了同样的问题org.webrtc:google-webrtc:1.0.22672。我使用的是安卓7.0设备。视频通话工作正常。问题在于屏幕共享。屏幕共享始终显示黑屏。

然后我添加了以下内容:

peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.getEglBaseContext(), rootEglBase.getEglBaseContext());

现在它工作得很好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WebRTC无法录屏 的相关文章

  • 使用 android 将图像上传到 Flickr

    我需要将 Flickr 与 android 集成 我已完成身份验证 我需要将图像上传到 flickr 但我不知道如何执行相同操作 我参考文件 http www flickr com services api upload api html
  • 如何在flutter android插件包中处理android生命周期

    我需要知道 android 插件包中 flutter 应用程序视图的当前状态 现在 我观察颤振视图中的状态https docs flutter io flutter widgets WidgetsBindingObserver class
  • Android Volley:意外响应代码 405

    我的 Android Volley JsonObjectRequest 遇到 onErrorResponse 并出现以下问题 BasicNetwork performRequest Unexpected response code 405
  • 将 React Native 应用程序嵌入到现有的 ios/android 应用程序中

    我需要知道是否可以在现有的 ios android 应用程序中 嵌入 一个 React Native 应用程序 而不共享 React Native 应用程序代码 我们目前有一个 React Native 应用程序 它使用一些插件依赖项 并被
  • SDK 管理器缺少模拟器的旧版 Android 系统映像

    我刚刚重新安装了 ADT 捆绑包 20130522 和 Android Studio 因为我的 eclipse 安装再次搞砸了 但那是另一个故事了 在任一版本中 当我启动 SDK Manager 时 都没有任何 2 2 的系统映像 只有 2
  • 检测Android N版本代码

    是否可以检测用户是否运行 Android N 我有一台装有 Android N 开发者预览版的 Nexus 6 如果我尝试获取构建版本Build VERSION SDK INT 它返回 23 等于 Android Marshmallow Q
  • 使用audioSessionId值实例化AudioFx类?

    我已经阅读了 Android API 并尝试在互联网上搜索有关声明自定义audioSessionId然后用它audioSessionId初始化 AudioFx 类并为我的 MediaPlayer 或 AudioTrack 分配硬编码audi
  • Google Play 服务,登录成功,但创建房间时出错

    我正在尝试 google play 服务示例 特别是 ButtonClicker2000 从 logcat 登录过程也正常 但我有另一个错误 06 01 22 43 15 478 D ButtonClicker2000 1565 Sign
  • Android TextView 中的等宽表格数字

    我有一个自定义字体 默认情况下具有可变宽度数字字形 并且我想在 Android 中使用该字体的等宽表格数字功能TextView使数字垂直对齐 也就是说 改变如下 像这样的事情 要选择字体的表格数字功能 请使用TextView s fontF
  • 视图随软键盘移动,遮挡其他 UI 对象

    我有一个容器视图 我希望它始终位于视图底部 位于 ScrollView 下方 ScrollView 有一些 UI 对象 其中一个是 EditText 对象 目前 当用户点击 EditText 对象内部时 android softkeyboa
  • java.exe 以非零退出值 1 结束

    只是为了开始 我并不是真正尝试从 Android 中的 xlsx 文件中读取单元格 我已经尝试了几乎所有我在 Google 上搜索到的内容 但是每次 在两台不同的 PC 上 都是 Java 1 7 0 79 当我尝试构建 运行 这个应用程序
  • Android 中的 BLE Gatt onConnectionStateChanged 失败,状态为 257

    我正在开发一个同时连接到多个BLE设备的Android应用程序 之后我从这些设备永久读取特征 但过了一会儿 我在onConnectionStateChanged 函数中得到状态257 android文档没有解释错误的原因是什么 或者如何修复
  • 从字符串中删除重音符号

    Android 中有没有什么方法 据我所知 没有 java text Normalizer 可以从字符串中删除任何重音 例如 变成 eau 如果可能的话 我想避免解析字符串来检查每个字符 java text NormalizerAndroi
  • 在异步请求中使用超时回调

    我之前问过这个问题 但我将用提出的解决方案来完成这个问题 并提出另一个问题 我正在使用这个类来进行异步网络请求 http msdn microsoft com en us library system net webrequest aspx
  • 如何在捆绑中存储稀疏数组

    我有一个SparseArray
  • 地理围栏不可用以及如何处理

    我正在 Android 上使用地理围栏 它在大多数手机上都工作正常 但在其中一些上 它不起作用 在我的错误日志中显示 地理围栏不可用 某些用户没有为 Google Play 服务启用位置跟踪 我认为这就是地理围栏在他们的手机上不起作用的原因
  • 什么是版本代码主要?和versionCode有什么区别?

    我刚刚发现PackageInfo versionCode https developer android com reference android content pm PackageInfo html versionCode在 Andr
  • 调用外部应用程序

    如何从我的应用程序调用外部应用程序 例如 我需要打电话Shazam 应用程序 来自我的应用程序 我可以在应用程序的包名称中看到logcat 这对任何目的都有用吗 特别是对于 Shazam 以下代码有效 Intent intent new I
  • FragmentMap + ActionBar 选项卡

    我一直在尝试插入一个MapView进入一个ActionBar Tab 但我什至无法解决问题 即使谷歌搜索 这是主要活动 Override public void onCreate Bundle savedInstanceState supe
  • 如何获取视图到手机底部的距离?

    如果我在布局上有某个视图 ImageView 例如 是否可以找到View的下边框到手机屏幕底部的距离 Thanks instantiate DisplayMetrics DisplayMetrics dm new DisplayMetric

随机推荐

  • 如何使用 Spring RestTemplate 禁用 SSL 证书检查?

    我正在尝试编写一个集成测试 我们的测试使用以下命令启动嵌入式 HTTPS 服务器Simple http www simpleframework org I 使用创建了一个自签名证书keytool https www sslshopper c
  • Android aar依赖

    我是 Gradle 构建系统的新手 我有一个库项目 其中包括 Retrofit okhttp 等依赖项 我编译了我的项目并创建了一个 aar 文件 我创建了一个虚拟项目并将我的库 aar 添加为依赖项 现在 如果我不在我的虚拟应用程序的 b
  • 有效读取SO的数据转储

    我目前使用 Vim 来阅读SO的数据转储 https blog stackoverflow com 2009 06 stack overflow creative commons data dump 然而 当我只向下滚动几行时 我的 Mac
  • Python高精度整数到numpy整数数组

    我明白那个numpy无法处理非本机整数 但是如何将 python 高精度整数存储为array本机整数 以任一字节序 例如 a 105951305240504794066266398962584786593081186897777398483
  • C++ Boost ASIO async_send_to 内存泄漏

    我目前正在开发 UDP 套接字客户端 我目前注意到内存泄漏 并且尝试了几种方法希望消除它 但它仍然存在 在我的主要内容中 我有一个char 那已经是malloc d 然后我调用以下函数来发送数据 void Send const char d
  • 我可以使用 node.js 获取唯一的服务器计算机标识符吗?

    我想知道是否有一种方法可以让 NODE 检索其运行的服务器的 MAC 地址 Node没有内置的方法来访问这种低级数据 但是 您可以执行ifconfig并解析其输出或为节点编写 C 扩展 以提供检索 mac 地址的函数 更简单的方法是阅读 s
  • Clojure 中复杂的数据操作

    我正在从事一个个人市场分析项目 我有一个代表市场最近所有转折点的数据结构 如下所示 high 1 121455 time 2016 08 03T05 15 00 000000Z low 1 12109 time 2016 08 03T05
  • 为什么我的 ScrollViewer 会破坏我的网格布局? WPF

    问题 当在网格周围添加 ScrollViwer 时 网格缩放被取消 埃克桑佩尔 我创建了一个 3 列的网格宽度 1 coulymn 应始终比第 2 列和第 3 列大 2 倍 如果没有 ScrollViewer 这总是正确的 但是当添加它时
  • 交互式关闭键盘时如何检测键盘框架的变化?

    考虑这种情况 我有一个文本视图 在情节提要中以交互方式设置了键盘关闭 因此当用户向下滚动并能够以交互方式关闭键盘时 我对文本视图底部有限制 以确保它始终完全显示在视图上 当前的问题是 当用户逐渐向下滚动以关闭键盘时 我无法检测到键盘框架的变
  • 用于输入“新的或二手的”的布尔值与枚举

    我有一个也许很愚蠢的问题 我试图确定输入其值为 新 或 已用 的属性的最佳方法是什么 我是否使用enum或者我应该去boolean 例如 IsNew 如果我和enum 我应该如何称呼这个类型和属性名称 public NewOrUsed Ne
  • requests.exceptions.HTTPError: 429 客户端错误: url 请求过多

    我正在研究 pycharm Flask 我试图使用以下方法获取类似的新闻文章 from googlesearch import search 我还调用了所有必要的库 例如 pip install google pip install goo
  • 寻找良好的索引和稀疏矩阵方法来从现有矩阵创建矩阵

    我有一个形状为 M 3 的大型 numpy 数组 A 其每一行的元素都是唯一的 范围从 0 到 N 1 的非负整数 事实上 每一行对应于我的有限元分析中的一个三角形 例如 M 4 N 5 矩阵 A 如下所示 array 0 1 2 0 2
  • 两级缓存(Redis + Caffeine)

    在对应用程序进行分析时 我们发现 Redis 正在影响执行时间 因为线程中有很多睡眠 我需要实现两级缓存或考虑解决这个问题 我想要两级缓存 L1 每个部署实例的本地 L2 同一部署的所有实例的全局缓存 我想出的解决方案是 创建两个Cache
  • 我可以观察 UIViewController 何时更改界面方向吗?

    如果我有一个指向 UIViewController 的指针 我可以在它更改 interfaceOrientation 时收到通知 而无需修改控制器的代码吗 我最好的选择是检测设备方向的变化 然后查看 UIViewController 是否会
  • 已存在文件的概率 System.IO.Path.GetRandomFileName()

    最近我遇到了异常 Message System IO IOException The file C Windows TEMP 635568456627146499 xlsx already exists at System IO Error
  • 跨多个组件实例的 Angular 2 全局变量

    我在一个页面上有两个组件 Component1 和 Component2 其中每个内部都是 Component3 显然 每个组件 3 都是其自己的组件实例 但是 我想要两者之间的全局变量 我正在创建一些数据的并排比较 并且希望有一个手风琴能
  • 无法使用 kaaes Spotify Web api 获取播放列表的曲目

    我是一个非常菜鸟的用户 我正在尝试在我的 Android 应用程序中播放 Spotify 的一些曲目 目前我正在使用 kaaes API https github com kaaes spotify web api android http
  • 每天在数组中给定的动态时间自动触发本地通知 Objective c ios

    我有很多时间hoursArray和分钟数组minutesArray我得到了current date现在从系统中我有了包含当前月份元素的数组 这意味着如果 4 月有 30 天 我已将其插入到数组中的 hoursArray minesArray
  • HTML 5 拖动事件:“dragleave”在“dragenter”之后触发

    我在单页应用程序中使用 html5 Dragevents 目前 我正在听dragleave and dragenter事件来为元素设置正确的类 但是 当两个有效的目标元素 A 和 B 彼此相邻 并且我们将一个元素通过 A 拖入 B 时 事件
  • WebRTC无法录屏

    我正在尝试使用 WebRTC 制作屏幕共享应用程序 我有可以从相机获取和共享视频流的代码 我需要修改它以通过 MediaProjection API 获取视频 基于此post https groups google com d msg di