IVS 广播 SDK:混合设备 - Amazon IVS

IVS 广播 SDK:混合设备

混合设备是音频和视频设备,采用多个输入源并生成单个输出。混合设备是一项强大的功能,可让您定义和管理多个屏幕上的(视频)元素和音轨。您可以组合来自多个来源的视频和音频,例如摄像头、麦克风、屏幕截图以及应用程序生成的音频和视频。您可以使用转换围绕流式传输到 IVS 的视频移动这些源,然后在流中添加和移除源。

混合设备分为图像和音频两种。要创建一个混合图像设备,请调用:

Android 上的 DeviceDiscovery.createMixedImageDevice()

iOS 上的 IVSDeviceDiscovery.createMixedImageDevice()

返回的设备可以附加到 BroadcastSession(低延迟流式传输)或 Stage(实时流式传输),就像任何其他设备一样。

术语

IVS 广播混合设备术语。
租期 描述

设备

一种硬件或软件组件,用于生成到音频或图像输入。例如,设备包括麦克风、摄像头、蓝牙耳机和屏幕截图或自定义图像输入等虚拟设备。

混合设备

可以像其他任何 Device 一样附加到 BroadcastSessionDevice,但带有允许添加 Source 对象的附加 API。混合设备具有内部混合器,其合成音频或图像,从而产生单个输出音频和图像流。

混合设备分为音频或图像两种。

混合设备配置

混合设备的配置对象。对于混合图像设备,这将配置诸如尺寸和帧率之类的属性。对于混合音频设备,这将配置通道计数。

来源

定义视觉元素在屏幕上的位置以及音频混合中音轨属性的容器。可以使用零个或多个源配置混合设备。向源提供了影响源媒体使用方式的配置。上图显示了四个图像源:

  • 左下带摄像头输入

  • 右上带电影输入

  • 右下带有 Amazon IVS 徽标

  • 全屏背景图像

源配置

进入混合设备的源的配置对象。完整的配置对象如下所述。

Transition

要将插槽移动到新位置或更改其部分属性,请使用 MixedDevice.transitionToConfiguration()。此方法需要:

  • 表示源的下一个状态的新源配置。

  • 一个持续时间,该持续时间指定动画相对于视频的时间轴应该花费多长时间。如果持续时间设置为 0,则转换发生在混合的下一帧上。

  • 一个可选的回调函数,通知您动画的完成时间。回调可能对于链接动画很有用。

混合音频设备

配置

Android 上的 MixedAudioDeviceConfiguration

iOS 上的 IVSMixedAudioDeviceConfiguration

名称 类型 描述

channels

整数

音频混合器的输出通道数。有效值:1、2。1 为单声道音频;2 为立体声音频。默认值:2。

源配置

Android 上的 MixedAudioDeviceSourceConfiguration

iOS 上的 IVSMixedAudioDeviceSourceConfiguration

名称 类型 描述

gain

浮点型

音频增益。这是一个乘数,因此任何高于 1 的值都会提高增益;任何低于 1 的值都会减小增益。有效值:0-2。默认值:1。

混合图像设备

配置

Android 上的 MixedImageDeviceConfiguration

iOS 上的 IVSMixedImageDeviceConfiguration

名称 类型 描述

size

Vec2

视频画布的大小。

targetFramerate

整数

混合设备的每秒目标帧数。通常情况下,该值应能够得到满足,但是在某些情况下(例如 CPU 或 GPU 负载过高),系统可能会丢弃帧。

transparencyEnabled

布尔值

这允许使用图像源配置上的 alpha 属性进行混合。将其设置为 true 会增加内存和 CPU 消耗。默认值:false

源配置

Android 上的 MixedImageDeviceSourceConfiguration

iOS 上的 IVSMixedImageDeviceSourceConfiguration

名称 类型 描述

alpha

浮点型

插槽的 Alpha。这是与图像中的任何 Alpha 值相乘的结果。有效值:0-1。0 表示完全透明,1 表示完全不透明。默认值:1。

aspect

AspectMode

适用于插槽中渲染的任何图像的宽高比模式。有效值:

  • Fill — 保持图像的宽高比但填满插槽。必要时,图像被裁剪。

  • Fit — 保持图像的宽高比但将整个图像放入插槽中。必要时,插槽可能有一个宽银幕效果或左右黑边。如果设置了该值,宽银幕效果/左右黑边为 fillColor,否则,将为透明(如果图像后的画布颜色为黑色,它看起来可能是黑色)。

  • None — 请勿保持图像的宽高比。图像被缩放,以匹配插槽的尺寸。

默认值:Fit

fillColor

Vec4

当插槽和图像的宽高比不匹配时,填充用于 aspect Fit 的颜色。格式为(red、green、blue、alpha)。有效值(对于每个通道):0-1。默认值:(0, 0, 0, 0)。

position

Vec2

插槽相对于画布左上角的位置(以像素为单位)。插槽的原点也在左上角。

size

Vec2

插槽的大小(以像素为单位)。设置此值也会将 matchCanvasSize 设置为 false。默认值:(0, 0);但是,因为 matchCanvasSize 默认为 true,插槽的渲染大小就是画布大小,而不是 (0, 0)。

zIndex

浮点型

插槽的相对顺序。zIndex 值较高的插槽绘制在 zIndex 值较低的插槽之上。

创建和配置混合图像设备

配置广播会话以进行混合。

在这里,我们创建了一个类似于本指南开头的场景,其中包含三个屏幕元素:

  • 左下角的摄像头插槽。

  • 右下角的徽标叠加插槽。

  • 右上角用于电影的插槽。

请注意,画布的原点是左上角,插槽也是一样。因此,将插槽定位在 (0, 0) 会将其放在左上角,且整个插槽可见。

iOS

let deviceDiscovery = IVSDeviceDiscovery() let mixedImageConfig = IVSMixedImageDeviceConfiguration() mixedImageConfig.size = CGSize(width: 1280, height: 720) try mixedImageConfig.setTargetFramerate(60) mixedImageConfig.isTransparencyEnabled = true let mixedImageDevice = deviceDiscovery.createMixedImageDevice(with: mixedImageConfig) // Bottom Left let cameraConfig = IVSMixedImageDeviceSourceConfiguration() cameraConfig.size = CGSize(width: 320, height: 180) cameraConfig.position = CGPoint(x: 20, y: mixedImageConfig.size.height - cameraConfig.size.height - 20) cameraConfig.zIndex = 2 let camera = deviceDiscovery.listLocalDevices().first(where: { $0 is IVSCamera }) as? IVSCamera let cameraSource = IVSMixedImageDeviceSource(configuration: cameraConfig, device: camera) mixedImageDevice.add(cameraSource) // Top Right let streamConfig = IVSMixedImageDeviceSourceConfiguration() streamConfig.size = CGSize(width: 640, height: 320) streamConfig.position = CGPoint(x: mixedImageConfig.size.width - streamConfig.size.width - 20, y: 20) streamConfig.zIndex = 1 let streamDevice = deviceDiscovery.createImageSource(withName: "stream") let streamSource = IVSMixedImageDeviceSource(configuration: streamConfig, device: streamDevice) mixedImageDevice.add(streamSource) // Bottom Right let logoConfig = IVSMixedImageDeviceSourceConfiguration() logoConfig.size = CGSize(width: 320, height: 180) logoConfig.position = CGPoint(x: mixedImageConfig.size.width - logoConfig.size.width - 20, y: mixedImageConfig.size.height - logoConfig.size.height - 20) logoConfig.zIndex = 3 let logoDevice = deviceDiscovery.createImageSource(withName: "logo") let logoSource = IVSMixedImageDeviceSource(configuration: logoConfig, device: logoDevice) mixedImageDevice.add(logoSource)

Android

val deviceDiscovery = DeviceDiscovery(this /* context */) val mixedImageConfig = MixedImageDeviceConfiguration().apply { setSize(BroadcastConfiguration.Vec2(1280f, 720f)) setTargetFramerate(60) setEnableTransparency(true) } val mixedImageDevice = deviceDiscovery.createMixedImageDevice(mixedImageConfig) // Bottom Left val cameraConfig = MixedImageDeviceSourceConfiguration().apply { setSize(BroadcastConfiguration.Vec2(320f, 180f)) setPosition(BroadcastConfiguration.Vec2(20f, mixedImageConfig.size.y - size.y - 20)) setZIndex(2) } val camera = deviceDiscovery.listLocalDevices().firstNotNullOf { it as? CameraSource } val cameraSource = MixedImageDeviceSource(cameraConfig, camera) mixedImageDevice.addSource(cameraSource) // Top Right val streamConfig = MixedImageDeviceSourceConfiguration().apply { setSize(BroadcastConfiguration.Vec2(640f, 320f)) setPosition(BroadcastConfiguration.Vec2(mixedImageConfig.size.x - size.x - 20, 20f)) setZIndex(1) } val streamDevice = deviceDiscovery.createImageInputSource(streamConfig.size) val streamSource = MixedImageDeviceSource(streamConfig, streamDevice) mixedImageDevice.addSource(streamSource) // Bottom Right val logoConfig = MixedImageDeviceSourceConfiguration().apply { setSize(BroadcastConfiguration.Vec2(320f, 180f)) setPosition(BroadcastConfiguration.Vec2(mixedImageConfig.size.x - size.x - 20, mixedImageConfig.size.y - size.y - 20)) setZIndex(1) } val logoDevice = deviceDiscovery.createImageInputSource(logoConfig.size) val logoSource = MixedImageDeviceSource(logoConfig, logoDevice) mixedImageDevice.addSource(logoSource)

移除源

要移除源,请使用要移除的 Source 对象调用 MixedDevice.remove

动画转换

转换方法用新配置替换源的配置。通过将持续时间设置为大于 0(以秒为单位),可以将此替换制作为随时间推移的动画。

哪些属性可以制作成动画?

插槽结构中并非所有属性都可以制作成动画。基于 Float 类型的任何属性都可以制作成动画;其他属性在动画的开始或结束时生效。

名称 可以制作成动画吗? 影响点

Audio.gain

已插入

Image.alpha

已插入

Image.aspect

结束

Image.fillColor

已插入

Image.position

已插入

Image.size

已插入

Image.zIndex

注意:zIndex 在 3D 空间中移动 2D 平面,因此当两个平面在动画中间的某个点交叉时,就会发生转换。这可以计算出来,但具体取决于开始和结束 zIndex 值。为了实现更顺畅的转换,请将其与 alpha 结合使用。

未知

简单示例

以下是使用上述创建和配置混合图像设备中定义的配置进行全屏摄像头接管的示例。将其在 0.5 秒以内的变化制作成动画。

iOS

// Continuing the example from above, modifying the existing cameraConfig object. cameraConfig.size = CGSize(width: 1280, height: 720) cameraConfig.position = CGPoint.zero cameraSource.transition(to: cameraConfig, duration: 0.5) { completed in if completed { print("Animation completed") } else { print("Animation interrupted") } }

Android

// Continuing the example from above, modifying the existing cameraConfig object. cameraConfig.setSize(BroadcastConfiguration.Vec2(1280f, 720f)) cameraConfig.setPosition(BroadcastConfiguration.Vec2(0f, 0f)) cameraSource.transitionToConfiguration(cameraConfig, 500) { completed -> if (completed) { print("Animation completed") } else { print("Animation interrupted") } }

镜像广播

要在此方向镜像广播中附加的映像设备... 使用负值表示...

水平

插槽的宽度

垂直

插槽的高度

水平和垂直方向

槽的宽度和高度

需要按相同的值调整位置,以便在镜像时将槽置于正确的位置。

以下是水平和垂直镜像广播的示例。

iOS

水平镜像:

let cameraSource = IVSMixedImageDeviceSourceConfiguration() cameraSource.size = CGSize(width: -320, height: 720) // Add 320 to position x since our width is -320 cameraSource.position = CGPoint(x: 320, y: 0)

垂直镜像:

let cameraSource = IVSMixedImageDeviceSourceConfiguration() cameraSource.size = CGSize(width: 320, height: -720) // Add 720 to position y since our height is -720 cameraSource.position = CGPoint(x: 0, y: 720)

Android

水平镜像:

val cameraConfig = MixedImageDeviceSourceConfiguration().apply { setSize(BroadcastConfiguration.Vec2(-320f, 180f)) // Add 320f to position x since our width is -320f setPosition(BroadcastConfiguration.Vec2(320f, 0f)) }

垂直镜像:

val cameraConfig = MixedImageDeviceSourceConfiguration().apply { setSize(BroadcastConfiguration.Vec2(320f, -180f)) // Add 180f to position y since our height is -180f setPosition(BroadcastConfiguration.Vec2(0f, 180f)) }

注意:此镜像与 ImagePreviewView(Android)和 IVSImagePreviewView(iOS)上的 setMirrored 方法不同。该方法仅影响设备上的本地预览视图,不会影响广播。