UWP 手绘视频创作工具技术分享系列 - 手绘视频导出
手绘视频最终的生成物是视频文件,前面几篇主要讲的是手绘视频的创作部分,今天讲一下手绘视频的导出问题。主要以 UWP 为例,另外会介绍一些 Web 端遇到的问题和解决方法。
如上所述,手绘视频在创作后,最终会导出为视频文件,如 MP4,WMV 等,我们目前的选择是 MP4,整个导出大致分为几个步骤:
1. 后台渲染手绘视频
后台渲染我们借助的还是 Win2D,前面几篇介绍过,创作绘制过程也是借助 Win2D 来完成动态渲染的。把需要渲染的元素和指定的时间等属性传递给 Win2D,其他的由 Win2D 去完成,这里不多作介绍。
2. 按帧率定制截取图片
这个步骤的实现方式较多,我们使用的是 CanvasBitmap.CreateFromBytes 和 MediaClip.CreateFromSurface 的方式截图,并把每部分的视频片段文件保存下来,看一段示例代码:
var img = CanvasBitmap.CreateFromBytes(device, screen.GetPixelBytes(), (int)screen.SizeInPixels.Width, (int)screen.SizeInPixels.Height, screen.Format);
var clip = MediaClip.CreateFromSurface(img, span);
layerTmp.Overlays.Add(CreateMediaOverlay(clip, size, s - start));
var composition = new MediaComposition();
composition.Clips.Add(MediaClip.CreateFromSurface(bkScreen, TimeSpan.FromMilliseconds(s - start)));
composition.OverlayLayers.Add(layerTmp);
var mediaPartFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync($"part_{mediafileList.Count}.mp4", CreationCollisionOption.ReplaceExisting);
await composition.RenderToFileAsync(mediaPartFile, MediaTrimmingPreference.Fast, MediaEncodingProfile.CreateMp4(quality));
mediafileList.Add(mediaPartFile);
3. 图片序列生成视频
这一步骤,普遍来讲都是通过 FFMpeg 来实现,FFMpeg 在 C# 语言方面也有很多封装版本可用。不过我们在 UWP 中并没有使用 FFMpeg,一方面代码库体积较大,另一方面我们有 MediaComposition 和 MediaClip 可用。
我们使用前面步骤保存下来的视频片段,使用 MediaComposition.RenderToFileAsync 方法保存到视频文件 ××.mp4 中:
foreach (var mediaPartFile in mediafileList)
{
var mediaPartClip = await MediaClip.CreateFromFileAsync(mediaPartFile);
bkComposition.Clips.Add(mediaPartClip);
}
var saveOperation = bkComposition.RenderToFileAsync(file, MediaTrimmingPreference.Fast,
MediaEncodingProfile.CreateMp4(quality));
4. 处理插入视频的音轨
这一步骤操作相对简单,因为 MediaOverlay 对声音的支持很方便,我们只需要把插入的视频,按照设定的开始时间和结束时间做裁剪,然后做好指定的旋转等变换,接下来设置 MediaOvelay.AudioEnabled = true; 就可以了,如果需要对视频静音,就设置为 false。
var overlay = CreateMediaOverlay(overlayClip, size, effect.StartAt);
overlay.AudioEnabled = videoGlygh.IsEnableAudio;
layer.Overlays.Add(overlay);
bkComposition.OverlayLayers.Add(layer);
5. 处理视频背景音乐
处理背景音乐也是使用 MediaComposition 的 BackgroundAudioTracks,通过音频文件来创建 BackgroundAudioTrack。它是一个 iList 类型,也就是说我们可以加入多个音轨。看一下简单的示例代码:
StorageFile music = await StorageFile.GetFileFromApplicationUriAsync(new Uri(DrawOption.Instance.DefaultMusic.url));
var backgroundTrack = await BackgroundAudioTrack.CreateFromFileAsync(music);
bkComposition.BackgroundAudioTracks.Add(backgroundTrack);
这里需要处理一些特殊情况,比如手绘视频中允许音频文件循环播放,这时我们需要对音频文件做一下拼接,简单的根据视频时间和音频时间做一下手动拼接:
int i = ;
while (DrawOption.Instance.MusicLoop && duration.TotalMilliseconds * i < total)
{
var track = await BackgroundAudioTrack.CreateFromFileAsync(music);
track.Delay = TimeSpan.FromMilliseconds(i * duration.TotalMilliseconds);
bkComposition.BackgroundAudioTracks.Add(track);
++i;
}
到这里我们就完成了在 UWP 中导出手绘视频的工作,而导出时间一般和视频分辨率,渲染元素的复杂度有很大关联,目前 720P 视频的导出时间大概是手绘视频时长的 2 倍左右。当视频很长,比如超过 10 分钟时,导出时间会变得比较长,之前我们也 fix 过一个 bug,就是图片大量保存到本地时,本地磁盘 IO 变成了瓶颈,磁盘占用量也很高,后面针对这个 bug 做了修改,把本地保存文件改为内存中持有,做好 GC 工作。
这样一来,视频导出的时间消耗就可以接受了,同时我们还有 Web 端平台,它同样也具备手绘视频创作和导出的功能,它的导出功能是在服务器端完成的,服务器是 Linux,它并没有 UWP 这么幸运,它的导出工作运行起来比较缓慢,基本会在视频长度的 5- 10倍左右,流程如下:
这里影响导出时间的主要是 PhantomJS 的截图,它的性能不好,每帧图片截图的时间很久,拖慢了整体速度。而目前我们想到了,除了使用 C++ 重新写一下截图的功能,没有其他好的办法,而即使重写,效率提升也不会太大。
基于这些问题,我们想到了另一个解决办法,在用户本地,使用浏览器插件或本地应用程序,来完成转换并同步到服务器。下面简单说说我们目前尝试的几种方案:
1. 传统的录屏方案
在我们考虑把 Web 端视频生成转移到本地的第一时间,就想到了这个方案。实现方面相对于用户直接使用一个 3rdParty 的录屏软件,不同点就在于我们可以获取用户选择了什么音频作为背景音乐,我们可以把它上传到服务器端,展示在‘我的作品’列表里。流程如下图:
这种方式实现相对简单,基本就是 FFMpeg 的使用,但是弊端也很明显。因为是录屏,所以录制过程中,用户的浏览器不能移动、不能最小化、也不能暂停,而且必须预览完整的一遍,不可控性非常多,所以很快就被否决了。
2. Web 端结合本地程序方案
这个方案需要 Web 端和本地程序各自做一些事情,简单来说就是本地程序在本机启动一个服务,Web 端按照帧率在后台渲染的 Canvas 里截取图片传给本地程序,本地程序生成视频,合成音轨,上传到服务器,流程如图:
本地程序是一个后台服务,没有界面,不需要用户配合,浏览器只要不关闭就可以完成,用户不需要进行预览,这些就是这个方案的优点。目前这个方案正在开发中,开发完成后,我们会就这个方案详细做分享,还是一种很脑洞的实现方式。
到这里我们就讲解完毕了,UWP 的视频导出,Web 端视频导出的问题,以及目前我们想到的解决方案,如果大家有更好的办法,欢迎反馈给我们,感谢!
UWP 手绘视频创作工具技术分享系列 - 手绘视频导出的更多相关文章
- UWP 手绘视频创作工具技术分享系列 - 手绘视频与视频的结合
本篇作为技术分享系列的第三篇,详细讲一下手绘视频中结合视频的处理方式. 随着近几年短视频和直播行业的兴起,视频成为了人们表达情绪和交流的一种重要方式,人们对于视频的创作.编辑和分享有了更多的需求.而视 ...
- UWP 手绘视频创作工具技术分享系列
开篇先来说一下写这篇文章的初衷. 初到来画,通读了来画 UWP App 的代码,发现里面确实有很多比较高深的技术点,同时也是有很多问题的,扩展性,耦合,性能,功能等等.于是我们决定从头重构这个产品,做 ...
- UWP 手绘视频创作工具技术分享系列 - 全新的 UWP 来画视频
从2017年11月开始,我们开始规划和开发全新的来画Pro,在12月23日的短视频峰会上推出了预览版供参会者体验,得到了很高的评价和关注度.吸取反馈建议后,终于在2018年1月11日正式推出了全新版本 ...
- UWP 手绘视频创作工具技术分享系列 - 有 AI 的手绘视频
AI(Artificial Intelligence)正在不断的改变着各个行业的形态和人们的生活方式,图像识别.语音识别.自然语言理解等 AI 技术正在自动驾驶.智能机器人.人脸识别.智能助理等领域中 ...
- UWP 手绘视频创作工具技术分享系列 - Ink & Surface Dial
本篇作为技术分享系列的第四篇,详细讲一下手绘视频中 Surface Pen 和 Surface Dial 的使用场景. 先放一张微软官方商城的图,Surface 的使用中结合了 Surface Pen ...
- UWP 手绘视频创作工具技术分享系列 - SVG 的解析和绘制
本篇作为技术分享系列的第一篇,详细讲一下 SVG 的解析和绘制,这部分功能的研究和最终实现由团队的 @黄超超 同学负责,感谢提供技术文档和支持. 首先我们来看一下 SVG 的文件结构和组成 SVG ( ...
- UWP 手绘视频创作工具技术分享系列 - 文字的解析和绘制
本篇作为技术分享系列的第二篇,详细讲一下文字的解析和绘制,这部分功能的研究和最终实现由团队共同完成,目前还在寻找更理想的实现方式. 首先看一下文字绘制在手绘视频中的应用场景 文字是手绘视频中很重要的表 ...
- UWP 手绘视频创作工具技术分享系列 - 位图的绘制
前面我们针对 SVG 的解析和绘制做了介绍,SVG 是图片的一种形式,而另一种很重要的图片是:位图,包括 png.jpeg.bmp 等格式.位图的基本规则是,组成的基本元素是像素点,由宽度 * 高度个 ...
- 恒天云技术分享系列5 – 虚拟化平台性能对比(KVM & VMware)
恒天云技术分享系列:http://www.hengtianyun.com/download-show-id-14.html 概述 本性能测试报告将详细陈述各虚拟化平台基准性能测试的主要结论和详细结果. ...
随机推荐
- 201521123098 《Java程序设计》第3周学习总结
1. 本周学习总结 1. 学习了类的创建: 2. 学会利用快捷方式完成变量的getter和setter的设定: 3. 学会了静态变量和非静态变量的区别和定义: 4. 学习了构造函数的基本编写方法. 大 ...
- 201521123069 《Java程序设计》 第3周学习总结
1. 本章学习总结 如果看不清楚可点击类与对象 2. 书面作业 Q1. 代码阅读 public class Test1 { private int i = 1;//这行不能修改 private sta ...
- 201521123018 《Java程序设计》第3周学习总结
1. 本章学习总结 1. 学习了类的创建: 2. 学会利用快捷方式完成变量的getter和setter的设定: 3. 学会了静态变量和非静态变量的区别和定义: 4. 学习了构造函数的基本编写方法. 2 ...
- 201521123063 java第一周总结
20152112306 <Java程序设计>第一周学习总结 1.本周学习总结(2.20-2.26) java语言的特点: (1)简约且简单 (2)平台无关性 (3)面向对象 (4)多线程. ...
- 201521123045 《JAVA程序设计》第1周学习总结 1
1. 本周学习总结 学习了入门的java知识,知道了jdk.eclipse等基础软件,了解了如何编译最基础的java程序.知道了java的基本原理以及java的几种数据类型.掌握使用简单编译器编写ja ...
- 201521123093 java 第十三周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...
- 201521123060 《Java程序设计》第13周学习总结
1.本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2.书面作业 1.网络基础 1.1比较ping www.baidu.com与ping cec.jmu.edu ...
- MarkDown换行
现象:1,MarkDown编辑两行显示,但是实际显示为一行: 2,编辑状态中空一行,此时显示为也空了一行,界面显示不友好: 解决:在第一行中最后输入至少2个空格+回车即可显示正常:
- 用List传递学生信息
集合在程序开发中经常用到,例如,在业务方法中将学生信息.商品信息等存储到集合中,然后作为方法的返回值返回给调用者,以此传递大量的有序数据. 本实例将使用List集合在方法之间传递学生的信息.实例效果如 ...
- C++移动构造函数以及move语句简单介绍
C++移动构造函数以及move语句简单介绍 首先看一个小例子: #include <iostream> #include <cstring> #include <cstd ...