You need to enable JavaScript to run this app.
导航
蒙版弹幕
最近更新时间:2025.11.20 18:58:24首次发布时间:2021.09.16 17:47:42
复制全文
我的收藏
有用
有用
无用
无用

蒙版弹幕功能可以在弹幕经过画面中的主体区域(如人像)时,智能地将其隐藏,实现“弹幕绕人走”的效果,从而在保证弹幕互动性的同时,避免遮挡视频的核心内容,极大地提升用户观看体验。该功能尤其适用于人物访谈、舞蹈视频、游戏直播等需要突出画面主体的场景。效果演示:
Image
本文将指导您如何基于应用中已有的弹幕渲染功能,实现播放器 SDK 提供的蒙版弹幕能力。

技术原理

蒙版弹幕的实现,是播放器 SDK 与您的弹幕渲染模块协作完成的:
Image

  1. SDK 输出蒙版信息:播放器 SDK 会根据当前视频帧的时间戳,实时输出一个描述画面主体轮廓的蒙版信息(一个 SVG 字符串)。SVG 示例如下:

    <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
     width="455px" height="256px" viewBox="0 0 455 256"
     preserveAspectRatio="xMidYMid meet">
    <g transform="translate(0,256) scale(0.1,-0.1)" fill="#000000">
    <path d="M0 1280 l0 -1280 694 0 695 0 19 53 c11 28 36 84 55 122 20 39 45 104 56 145 18 67 48 157 96 290 9 25 22 52 30 60 42 49 89 220 99 363 7 100 51 230 89 264 12 11 63 33 112 47 50 15 117 35 150 45 56 17 60 20 63 51 3 30 -10 73 -61 195 -11 28 -24 70 -27 95 -4 25 -13 66 -21 92 -10 38 -11 61 0 125 14 91 17 187 7 224 -6 18 -3 31 9 42 20 21 68 22 84 3 25 -30 66 -29 133 5 112 57 218 33 288 -65 19 -27 61 -78 92 -113 36 -40 60 -77 64 -98 7 -37 -8 -121 -31 -169 -8 -17 -21 -59 -29 -94 -8 -34 -23 -77 -35 -95 -68 -108 -71 -126 -23 -164 20 -16 69 -47 107 -68 39 -20 106 -61 150 -90 44 -29 99 -62 122 -74 23 -11 48 -30 56 -41 11 -16 21 -19 40 -15 38 10 91 -11 132 -53 46 -47 57 -73 44 -110 -22 -65 -123 -81 -154 -24 l-14 27 -1 -35 c0 -19 7 -67 15 -105 8 -39 15 -86 15 -105 1 -33 4 -36 65 -64 119 -53 150 -110 120 -218 -17 -63 -87 -220 -111 -248 -12 -15 -114 -190 -114 -196 0 -2 331 -4 735 -4 l735 0 0 1280 0 1280 -2275 0 -2275 0 0 -1280z"/>
    </g>
    </svg>
    

    上述 SVG 效果图如下:
    Image

  2. 接收并处理蒙版:您需要通过代理回调接收这个 SVG 字符串,并将其转换为一个图片 UIImage

  3. 应用为视图遮罩:最后,将这张实时更新的蒙版图片,设置为您的弹幕渲染视图的 maskView。iOS 系统会自动根据 maskView 的不透明区域来决定弹幕视图哪些部分应该被显示,从而实现弹幕的动态遮挡效果。
    Image

前提条件

  • 已实现弹幕渲染:本文档假设您的 App 中已经有了一套自己的弹幕渲染系统(即您有一个用于显示弹幕的 UIView)。
  • 完成服务端配置
    • 生成蒙版文件:您需要通过视频点播媒体处理服务生成蒙版弹幕文件
    • 正确签发 PlayAuthToken(仅限 Vid 模式):如果您使用 Vid 模式播放,应用服务端在为客户端签发 PlayAuthToken 时,必须额外签入 "NeedBarrageMask" 字段。

实现步骤

步骤 1:开启蒙版弹幕功能

在初始化 TTVideoEngine 和播放过程中,通过 setOptionForKey 方法开启相关功能开关。

// 1. 在 TTVideoEngine 初始化时,开启蒙版弹幕的功能线程。
// 建议根据一个全局配置来决定是否开启。
[self.videoEngine setOptionForKey:VEKeyPlayerEnableBarrageMaskThread_BOOL value:@(YES)];

// ... 在播放器准备播放时 ...

// 2. 在视频播放过程中,您可以随时通过此开关控制蒙版的开启或关闭。
// isEnabled 是您自己的业务逻辑变量,例如用户点击了“开启/关闭蒙版”按钮。
BOOL isEnabled = YES; 
[self.videoEngine setOptionForKey:VEKKeyPlayerBarrageMaskEnabled_BOOL value:@(isEnabled)];

步骤 2:设置视频源与蒙版源

根据您的播放方式,设置视频源和蒙版源。

  • 对于 Vid 播放源,SDK 会自动关联蒙版信息,您无需额外设置蒙版 URL。

    // 与普通 Vid 播放的设置完全相同。
    TTVideoEngineVidSource *source = [[TTVideoEngineVidSource alloc] initWithVid:self.vid 
                                                                   playAuthToken:self.playAuthToken 
                                                                      resolution:resolution];
    [self.engine setVideoEngineVideoSource:source];
    
  • 对于 Url 播放源,您需要额外通过 setBarrageMaskURL: 方法指定蒙版文件的 URL。

    // 1. 设置视频播放源
    TTVideoEngineUrlSource *source = [[TTVideoEngineUrlSource alloc] initWithUrl:videoUrl cacheKey:cacheKey];
    [self.engine setVideoEngineVideoSource:source];
    
    // 2. 设置与该视频关联的蒙版文件 URL
    [self.engine setBarrageMaskURL:maskUrl];
    

步骤 3:接收并渲染蒙版

您需要设置 TTVideoEngineMaskDelegate 代理,以实时接收 SDK 回调的 SVG 蒙版信息,并将其渲染到一个用于做遮罩的 UIImageView 上。

  1. 请确保您的项目中已集成了 SVGKit 库,用于解析 SVG。

    // Podfile
    pod 'SVGKit'
    
  2. 在您的播放器 UIViewController 中,实现代理回调方法。

    #import <SVGKit/SVGKit.h>
    
    // 确保您的 ViewController 遵循 TTVideoEngineMaskDelegate 协议
    // @interface YourViewController () <TTVideoEngineMaskDelegate>
    
    #pragma mark - TTVideoEngineMaskDelegate
    
    /**
     * 当有新的蒙版信息时,此方法会被调用。
     * @param videoEngine 播放器实例
     * @param svg 当前帧的蒙版 SVG 字符串
     * @param pts 当前帧的时间戳
     */
    - (void)videoEngine:(TTVideoEngine *)videoEngine onMaskInfoCallBack:(NSString *)svg pts:(NSUInteger)pts {
        
        // SVG 解析和 UIImage 转换是耗时操作,应在后台线程执行。
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 1. 使用 SVGKit 将 SVG 字符串转换为 SVGKImage 对象。
            SVGKImage *svgkImage = [SVGKImage imageWithData:[svg dataUsingEncoding:NSUTF8StringEncoding]];
            
            // 获取转换后的 UIImage。
            UIImage *maskUIImage = svgkImage.UIImage;
            
            // 更新 UI 必须返回主线程。
            dispatch_async(dispatch_get_main_queue(), ^{
                if (maskUIImage) {
                    // 2. 将生成的图片设置为我们遮罩视图的内容。
                    // self.maskView 是一个 UIImageView 实例,专门用于承载蒙版。
                    self.maskView.image = maskUIImage;
                }
            });
        });
    }
    

步骤 4:应用蒙版遮罩

将承载着实时蒙版图片的 maskView 设置为您的弹幕渲染视图maskView 属性。

// 设置 maskView 之前先根据视频内容更新 frame
// Frame 计算参考:
// x = (playerView.bounds.size.width - videoWidth) / 2
// y = (playerView.bounds.size.height - videoHeight) / 2
// convertRect:toView:
_maskView.frame = CGRectMake(x, y, videoWidth, videoHeight);
// renderView:弹幕的渲染视图
// _maskView: 上述获取到的包含蒙版信息的 mask view.
[renderView setMaskView:_maskView];

至此,蒙版弹幕功能的核心流程已全部完成。

布局与适配

视图层级建议

合理的视图层级是保证功能正常显示和交互的前提。开发者可根据弹幕是否需要与播放器控制层进行交互,来选择适合当前业务的视图层级。以下提供两种常见的层级结构(由下至上)供您参考:
第一种(推荐):

PlayerView
├─ 视频渲染内容 (Video Content)
├─ PlayerControlsView    <-- 播放器控制层
└─ DanmakuContainerView  <-- 弹幕的容器视图
   └─ danmakuRenderView   <-- 您的弹幕渲染视图,其 maskView 已被设置
  • 优点:便于实现交互式弹幕,易扩展,视图层级较少,交互类控件和弹幕集中在播放控制 View 中。
  • 缺点:和其他播放控制耦合较多。

第二种:

PlayerView
├─ 视频渲染内容 (Video Content)
├─ DanmakuContainerView  <-- 弹幕的容器视图
│  └─ danmakuRenderView   <-- 您的弹幕渲染视图,其 maskView 已被设置
└─ PlayerControlsView    <-- 播放器控制层(按钮、进度条等)
  • 优点:易实现
  • 缺点:仅适用于非交互式弹幕

处理横竖屏切换与视图尺寸变化

当设备旋转或播放器视图尺寸发生变化时,视频内容的实际渲染区域也会随之改变。此时,您必须重新计算视频内容的 frame,并更新 maskViewframe,以确保蒙版与视频内容始终保持对齐。

_maskView.frame = CGRectMake(x, y, videoWidth, videoHeight);

// 必要时调用, renderView 是弹幕的渲染视图
[renderView setNeedsLayout];
[renderView layoutIfNeeded];