Android - 使用 Agora.io 进行屏幕共享

Posted

技术标签:

【中文标题】Android - 使用 Agora.io 进行屏幕共享【英文标题】:Android - Screen Share using Agora.io 【发布时间】:2020-05-19 12:45:25 【问题描述】:

我正在尝试在 android 上使用 Agora.io 实现 屏幕分享。我尝试关注他们的演示,但是使用低级 Android 图形 API 的解决方案似乎有点过于复杂,所以我尝试使用 ImageReader。

从我的活动中,我创建了一个服务(ShareScreenService 继承自 Service)

要开始屏幕共享,我会关注

private void StartScreenShare(int resultCode, Intent resultData)
        
            var mediaProjectionManager = (MediaProjectionManager)GetSystemService(MediaProjectionService);
            var mediaProjection = mediaProjectionManager.GetMediaProjection(resultCode, resultData);
            _shareScreenImageAvailableListener = new ShareScreenImageAvailableListener(this);
            var virtualDisplay = mediaProjection.CreateVirtualDisplay("sharescreen", Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels, (int)Resources.DisplayMetrics.DensityDpi, DisplayFlags.SupportsProtectedBuffers | DisplayFlags.Presentation, _shareScreenImageAvailableListener.Surface, null, _handler);
            var mediaProjectionCallback = new MediaProjectionCallback(virtualDisplay);
            mediaProjection.RegisterCallback(mediaProjectionCallback, _handler);

            AgoraVideoService.Instance.StartScreenShare();
        

AgoraVideoService.Instance.StartScreenShare does following:

internal void StartScreenShare()
        
            _agoraEngine.SetExternalVideoSource(true, false, true);
        

我的 ShareScreenImageAvailableListener 看起来像这样:

public class ShareScreenImageAvailableListener : Java.Lang.Object, ImageReader.IOnImageAvailableListener
    
        private ScreenShareService _screenShareService;
        private ImageReader _imageReader;

        public Surface Surface
        
            get
            
                return _imageReader.Surface;
            
        

        public ShareScreenImageAvailableListener(ScreenShareService screenShareService)
        
            _screenShareService = screenShareService;
            _imageReader = ImageReader.NewInstance(_screenShareService.Width, _screenShareService.Height, Android.Graphics.ImageFormatType.Jpeg, 1);
            _imageReader.SetOnImageAvailableListener(this, _screenShareService.Handler);
        

        public void OnImageAvailable(ImageReader reader)
        
            using (var image = reader.AcquireLatestImage())
            
                using (var planes = image.GetPlanes()[0])
                
                    using (var buffer = planes.Buffer)
                    
                        byte[] bytes = new byte[buffer.Capacity()];
                        buffer.Get(bytes);

                        _screenShareService.ShareScreenImage(bytes, image.Height, image.Format, planes.PixelStride);
                    
                
                image.Close();
            
        
    

那么在分享ShareScreenImage时:

internal void ShareScreenImage(byte[] bytes, int height, ImageFormatType format, int pixelStride)
        
            var agoraVideoFrame = new AgoraVideoFrame()
            
                Buf = bytes,
                Height = height,
                Format = (int)format,
                Stride = pixelStride,
                TimeStamp = DateTime.UtcNow.Ticks,
               CropBottom = 0,
               CropLeft = 0,
               CropRight = 0,
               CropTop = 0
            ;

            AgoraVideoService.Instance.ShareExternalVideoFrame(agoraVideoFrame);
        

最后 ShareExternalVideoFrame 看起来像这样:

_agoraEngine.PushExternalVideoFrame(agoraVideoFrame);

最后,我的问题是:我的想法在实现这个方面是否正确?我可以使用 ImageReader 还是需要降低才能开始使用 Agora 演示实现中的 EglCore 等?

我可以验证 OnImageAvailable 是否被调用(多次调用,直到我停止它)PushExternalVideoFrame 返回“true”,看起来帧被成功推送

但是这不会产生任何结果,我看不到正在共享的屏幕。所以我至少会验证这是一个可能的解决方案。

【问题讨论】:

【参考方案1】:

使用 EglCore 更安全,因为使用 ImageReader 尚未经过测试可与 Agora 一起使用。您可以使用高级指南和示例应用程序来了解如何将其与 EglCore 一起使用。

这里是示例应用的链接:https://github.com/AgoraIO/Advanced-Video

这里是指南的链接:https://docs.agora.io/en/Video/custom_video_android?platform=Android

【讨论】:

以上是关于Android - 使用 Agora.io 进行屏幕共享的主要内容,如果未能解决你的问题,请参考以下文章

Agora.io 令牌问题 Android

如何在 Android 中保存 agora 流?

Android 平台的 Callkit 示例或示例以及 agora.io 调用服务

我正在使用适用于 Agora.io 的 Android SDK 并尝试实现实时音频广播。出现错误

用于 android kotlin 的 agora io 1on 1 视频聊天在 firebase 中生成令牌

agora.io Android SDK:如何获取所有远程用户“uid”