代码之家  ›  专栏  ›  技术社区  ›  Kubik

WebRTC无法录制屏幕

  •  2
  • Kubik  · 技术社区  · 8 年前

    我正在尝试使用webrtc制作屏幕共享应用程序。我有可以从摄像机获取和共享视频流的代码。我需要修改它来通过mediaprojection api获取视频。基于此 post 我已经修改了代码,使用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;
        }
    }
    

    ProxyVideoSink公司

    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),但是我已经在3个不同api级别的设备上测试了这段代码,所以我不怀疑是设备特定的问题。 我尝试构建另一个使用MediaProjectionAPI(不带WebRTC)的应用程序,我可以在SurfaceView中看到正确的输出。 我试过降低webrtc库的级别,但似乎没有任何效果。

    谢谢你的帮助。

    1 回复  |  直到 8 年前
        1
  •  4
  •   Aniruddh Parihar Master_T    7 年前

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

    然后我又补充了以下内容:

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

    现在它工作得很好。