Android - 使用 Agora.io 进行屏幕共享
Android - Screen Share using Agora.io
我正在尝试在 Android 上使用 Agora.io 实现 屏幕共享。我试着按照他们的演示进行操作,但是使用低级 Android 图形 API 的解决方案似乎有点太复杂了,所以我尝试使用 ImageReader 来解决这个问题。
从我的 activity 我创建了一个服务(ShareScreenService 从服务继承)
要在那里开始屏幕共享,我会执行以下操作
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 returns "true" 看起来帧已成功推送
但是这不会产生任何结果,我看不到正在共享的屏幕。所以我至少会验证这是一个可能的解决方案。
使用 EglCore 更安全,因为使用 ImageReader 尚未经过测试可与 Agora 一起使用。您可以使用高级指南和示例应用程序来了解如何将其与 EglCore 一起使用。
这是示例应用程序的 link:https://github.com/AgoraIO/Advanced-Video
这里是 link 指南:https://docs.agora.io/en/Video/custom_video_android?platform=Android
我正在尝试在 Android 上使用 Agora.io 实现 屏幕共享。我试着按照他们的演示进行操作,但是使用低级 Android 图形 API 的解决方案似乎有点太复杂了,所以我尝试使用 ImageReader 来解决这个问题。
从我的 activity 我创建了一个服务(ShareScreenService 从服务继承)
要在那里开始屏幕共享,我会执行以下操作
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 returns "true" 看起来帧已成功推送
但是这不会产生任何结果,我看不到正在共享的屏幕。所以我至少会验证这是一个可能的解决方案。
使用 EglCore 更安全,因为使用 ImageReader 尚未经过测试可与 Agora 一起使用。您可以使用高级指南和示例应用程序来了解如何将其与 EglCore 一起使用。
这是示例应用程序的 link:https://github.com/AgoraIO/Advanced-Video
这里是 link 指南:https://docs.agora.io/en/Video/custom_video_android?platform=Android