zoukankan      html  css  js  c++  java
  • 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 = 1;
     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 端视频导出的问题,以及目前我们想到的解决方案,如果大家有更好的办法,欢迎反馈给我们,感谢!

  • 相关阅读:
    加快火狐启动速度的几种方法 Leone
    我国的社保到底是多交好,还是少交好? Leone
    “情商”和“智商”究竟有哪些区别? Leone
    Atitti 知识图谱构建方法attilax 总结
    Atitit 知识图谱的数据来源
    Atitit java 二维码识别 图片识别
    Atitit 跨平台异常处理(2)异常转换 java c# js异常对象结构比较and转换
    Atitit 异常机制与异常处理的原理与概论
    Atitti knn实现的具体四个距离算法 欧氏距离、余弦距离、汉明距离、曼哈顿距离
    屏幕取词技术实现原理
  • 原文地址:https://www.cnblogs.com/shaomeng/p/7680210.html
Copyright © 2011-2022 走看看