如何让添加到MediaClip的每个VideoEffect实例展示不同数据
解决方案
1. 构造VideoEffectDefinition时传入自定义参数
VideoEffectDefinition支持第二个构造参数,类型为IPropertySet,你可以将每个剪辑对应的字幕文本、坐标、字号等自定义参数通过这个参数传入不同的效果实例:
// 为第一个剪辑创建带参数的效果定义 var clip0Props = new Windows.Foundation.Collections.PropertySet(); clip0Props.Add("SubtitleText", "第一个剪辑的字幕"); clip0Props.Add("TextX", 100f); clip0Props.Add("TextY", 800f); composition.Clips[0].VideoEffectDefinitions.Add(new VideoEffectDefinition(typeof(MyVideoEffect).FullName, clip0Props)); // 第二个剪辑传入不同参数 var clip1Props = new Windows.Foundation.Collections.PropertySet(); clip1Props.Add("SubtitleText", "第二个剪辑的字幕"); clip1Props.Add("TextX", 100f); clip1Props.Add("TextY", 800f); composition.Clips[1].VideoEffectDefinitions.Add(new VideoEffectDefinition(typeof(MyVideoEffect).FullName, clip1Props)); // 第三个剪辑同理 var clip2Props = new Windows.Foundation.Collections.PropertySet(); clip2Props.Add("SubtitleText", "第三个剪辑的字幕"); clip2Props.Add("TextX", 100f); clip2Props.Add("TextY", 800f); composition.Clips[2].VideoEffectDefinitions.Add(new VideoEffectDefinition(typeof(MyVideoEffect).FullName, clip2Props));
2. 自定义效果类实现IMediaExtension接口接收参数
所有UWP自定义媒体效果都需要实现IMediaExtension接口,系统会在效果实例初始化时自动调用SetProperties方法,将你传入的参数集合传递给效果实例,你只需要将参数存为私有字段供ProcessFrame调用即可:
public sealed class MyVideoEffect : IMediaExtension, IBasicVideoEffect { // 存储传入的参数 private string _subtitleText = string.Empty; private float _textX = 100f; private float _textY = 800f; private CanvasDevice canvasDevice; // 实现IMediaExtension接口的SetProperties方法,接收传入的参数 public void SetProperties(IPropertySet configuration) { if (configuration.TryGetValue("SubtitleText", out object textObj)) { _subtitleText = textObj as string ?? _subtitleText; } if (configuration.TryGetValue("TextX", out object xObj)) { _textX = xObj is float x ? x : _textX; } if (configuration.TryGetValue("TextY", out object yObj)) { _textY = yObj is float y ? y : _textY; } } // 你的原有ProcessFrame逻辑,直接使用存储的参数即可 public void ProcessFrame(ProcessVideoFrameContext context) { using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromDirect3D11Surface(canvasDevice, context.InputFrame.Direct3DSurface)) using (CanvasRenderTarget renderTarget = CanvasRenderTarget.CreateFromDirect3D11Surface(canvasDevice, context.OutputFrame.Direct3DSurface)) using (CanvasDrawingSession ds = renderTarget.CreateDrawingSession()) { // 可根据需要扩展文字格式参数 CanvasTextFormat textFormat = new CanvasTextFormat() { FontSize = 40, HorizontalAlignment = CanvasHorizontalAlignment.Left }; CanvasTextLayout textLayout = new CanvasTextLayout(canvasDevice, _subtitleText, textFormat, renderTarget.Size.Width, renderTarget.Size.Height); ds.DrawTextLayout(textLayout, _textX, _textY, Colors.Yellow); } } // 其余IBasicVideoEffect接口的必要实现(你原有代码应该已经实现,这里省略) public bool IsReadOnly => false; public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties => new List<VideoEncodingProperties>(); public MediaMemoryTypes SupportedMemoryTypes => MediaMemoryTypes.Gpu; public void Close(MediaEffectClosedReason reason) { /* 原有资源释放逻辑 */ } public void DiscardQueuedFrames() { /* 原有逻辑 */ } public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device) { canvasDevice = CanvasDevice.CreateFromDirect3D11Device(device); /* 其余原有初始化逻辑 */ } }
注意事项
- 传入
PropertySet的参数只支持WinRT基础类型(字符串、数值、布尔值等),不支持自定义类实例 SetProperties会在效果实例初始化时、首次调用ProcessFrame之前执行,不需要额外做同步处理- 每个剪辑的效果实例是完全独立的,存储的参数不会互相干扰,完全不需要计时器或者其他额外逻辑来区分不同剪辑的字幕
内容的提问来源于stack exchange,提问作者M Psyllakis
相关产品推荐
相关产品推荐

