前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Instagram视频上传延迟优化

Instagram视频上传延迟优化

作者头像
LiveVideoStack
发布于 2019-07-01 02:59:41
发布于 2019-07-01 02:59:41
2.7K0
举报
文章被收录于专栏:音视频技术音视频技术

视频传输延迟,尤其是在某些互动社交环境中,会严重影响用户的体验。Instagram多年来以降低视频上传延迟为重要指标,实现了多种优化策略。本文来自Instagram媒体基础设施团队软件工程师Ryan Peterman。

文 / Ryan Peterman

译 / 蒋默邱泽

原文

https://instagram-engineering.com/video-upload-latency-improvements-at-instagram-bcf4b4c5520a

2013年6月,Instagram推出视频上传功能。当时系统功能很简单,为了摄取视频并用于播放。我们让Instagram app在客户端完成录制后将整段视频文件传至服务器,然后我们将视频转码为一组质量可控的视频版本,以确保视频文件可以在尽可能多的设备上播出。一旦所有视频都可用我们就“发布”供用户观看。

一个简单视频上传流程
一个简单视频上传流程

Instagram在社交环境中对上传时间反应尤为敏感,用户希望其他人可以尽快看到他们的视频故事和实时消息留言。出于这个原因上传延迟是Instagram一个非常重要的指标。多年来,我们开发出了多种减少延迟的策略。

让我们首先定义本文中的上传延迟,即服务器从客户端接收到所有视频码率信息,直至视频"可发布"或可供查看为止。

发布内容

减少视频上传延迟最简单的优化是在视频被发布前尽可能减少步骤。我们的想法是在所有视频版本都可用之前,先将可用的最高质量视频版本发布出去。其余视频可用于回放并非强制性,可以为带宽弱的用户提供较少卡顿的回放体验。这样可以有效降低处理低质量视频比高质量版本花费更多时间而造成的延迟,极大程度上提高了视频上传的成功率。因为我们只依赖一个版本而不是所有质量版本。

发布内容仅取决于高质量的版本
发布内容仅取决于高质量的版本

我们使用基于图形的存储系统来表示视频数据模型,所有视频版本"视频资源附加到父节点,这允许上传的视频被判断为媒体级别而不是视频版本级别。这种抽象实现了简单统一的发布逻辑。为了实现上述改进,我们将视频资源标记为“可发布的”,当我们通过视频处理服务收到回调信息时在视频资源中进行翻转布尔值。

通过让发布信号只依赖于一个版本,使得我们的视频处理模型更具弹性和灵活机制。如果通道在一段时间内无法生成可选编码,我们仍然可以准许发布视频,因为我们拥有最高质量版本。之后我们可以按需补充其余版本。

为了使发布信号只依赖于最高质量的版本,带宽受限的用户可能会体验次优的回放体验,直到其余版本完成为止。例如,只要最高质量的版本准备好了,视频就会发布,但是可能还有一些低质量的版本正在处理中,这些版本要到稍后才能发布。当带宽受限的用户最初观看视频时,如果只有最高质量的视频可用,他们可能会体验到相对较高的卡顿率与失帧率。而实际上在绝大多数情况下,编码的其余部分在强制的版本完成后也会迅速可用。

视频切片上传处理

另一种加快视频上传速度的方法是让客户端在视频录制完成后对其进行切片。一旦视频被切片,客户端就会把它们上传到服务器上,并给每个切片加上索引,以便后续可以按顺序重新组合。当服务器接收到视频切片时,并行地进行代码转换,从而节省时间。一旦所有切片都被转码,将其组合在一起,就可以进行播放。

通道处理部分被切片且并行
通道处理部分被切片且并行

在服务端,我们将每个视频处理流水线构建为有向非循环图。每个节点都是执行单元,每个边则代表两个节点间的依赖关系。每个节点在所有依赖项完成后执行运行。这里的示例是基本非分段通道简化处理视频过程:

在示例中大部分工作都发生在转码节点中。如果能并行化这部分,我们就可以显著减少上传延时。切片通道旨在通过为每个片段添加转码任务来并行化该部分。然后,添加一个拼接任务,将每个片段的视频帧连接起来,放在一个新的容器中。此拼接任务取决于通道每个片段任务,如下图:

在多数情况下切片上传只会减少上传延时,但质量权衡还有其他复杂性。例如:切片上传会增加通道复杂性。有一些质量指标会在转码时用于每个案例如SSIM。这些指标对我们每个细分受众群没有帮助。但是我们需要对所有片段的SSIM进行持续时间平均加权,以得出整个视频的SSIM。同样处理异常更加复杂,因为要处理非常多数量的计算单元。

此外通过切片视频,我们在通道引入另一个步骤将所有转码片段拼接在一起。这需要更多CPU处理,若是非切片则不必。重要问题是拼接步骤在最终系统中明显增加了I/O要求,每个片段在单个机器进行转码拼接时我们希望执行拼接处理。因此其他节点必须从网络下载所有片段这会大大增加I/O利用率。

在切片长度上我们会处理的非常小,这样可以并行完成更多任务。然而,由于设置节点对切片进行转码时存在一些必须开销,因此我们将切片长度保持在某个阈值以上。如果切片长度细分的太小,那么必然浪费资源。实际上将长度设置为大约几秒的时间对我们来说足以。

此外就上传延时而言,这并不总是全胜法子。随着初始视频缩短切片上传的好处也相应减少了。例如:下面描述了短视频和长视频的非分段视频处理和分段视频处理相对于时间的比较。对于这两者,我假设视频处理时间与视频长度成正比图。Δt 是切片和非切片通道执行之间的上传延时。与长视频相比,短视频的获胜几率要小得多:

总的来说,我们决定在上传过程的开始阶段根据产品和视频的长度对视频进行切片。某些视频产品(例如故事情节)已经强制规定了长度的最大值,这些最大值足够短,切片不需要特别复杂。对于像IGTV这样的视频产品,规定了最小长度,这样有足够的长度使得分片上传是有价值的。

透传

我们用来改进上传延迟和节省CPU利用率的另一种性能优化称为“透传”上传。在某些情况下,上传的媒体已经可以在大多数设备上播放了。如果是这样,我们可以完全跳过视频处理并将视频直接存储到数据模型中。这样不仅减少了延迟而且在这种情况下我们不需要对视频进行转码。

 透传检测是发布前的关键
透传检测是发布前的关键

这是一个非常重要的检查步骤,以便进入Instagram的视频符合我们的播放标准。除了视频转码通道外,我们还添加了另一种通道用于检测传入视频的特定属性。例如:编解码器和码率,以确认是否视频符合透传的条件。如果视频的解码器支持较少,那么能够播放视频的Instagram用户就会更少。类似地,如果比特率过高,则通过网络加载用于回放的视频将花费太长时间。

一旦解码器和码率通过我们的筛选标准,我们就会使用内部工具检查视频文件;该工具报告拓扑、一致性和存储流一致性。如果视频文件不一致,尝试修复原视频文件会被启用。这个内部工具可以可靠的识别缓冲区溢出场景,使得我们不会向用户提供任何恶略质量文件。最后我们将修复后的视频与原始视音频一起转码并存储在我们的数据模型中:

由此产生的透传通道比转码通道完成得更迅速。我们检查确保视频版本的可播放性,因此系统允许将资源池视频回调并标记发布状态。这极大地改善了视频处理延时并提高了视频质量,因为转码是一个有损的过程。

这里的权衡也取决于我们设定的码率上限,其原因有几种:如果原始视频的码率太高并且执行透传上传,那么我们将存储比转码视频时更大的文件。此外,随着码率的增加视觉质量反而在减少,当这些内容在屏幕尺寸有限的移动设备上播放时则更加明显。而高码率的原始视频在透传版本与高质量转码版本比较时,获得的视觉质量优势较小。实际上,我们的比特率上限允许我们控制这些权衡。

总而言之,透传对于依赖延迟的视频产品尤其有用。

下一步呢?

多年来,Instagram的视频处理能力有了显著提高。这种基础设施以高效、可靠和高质量方式为全球用户提供了丰富的价值。我们也在致力于使上述程序更加高效简单。

随着视频的老化和与外界的互动,一个最有希望的领域是根据需要生成和清除编码。

例如,我们可能希望根据流行程度或视频的年龄等数据更改某个视频的表示形式。由于旧的内容没有那么多的观看,我们不可能存储所有的视频版本。取而代之的是,我们可以只为那些看起来很久以前的小流量设置一个视频版本的子集。如果一个旧视频突然流行起来,那么我们可能会根据需要重新生成这些版本。

设计一个系统来管理我们在每个视频生命周期中所拥有的视频表示形式涉及到许多有趣的挑战。我们应该选择使用什么信号?如何快速有效地管理和迭代现有的视频?

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
QThread源码浅析[通俗易懂]
Qt版本 Qt5.6.0,下面以Windows平台为例简单研究下QThread源码实现。
全栈程序员站长
2022/09/02
5960
【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )
1. 线程创建方法函数原型 : int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void*), void *arg);
韩曙亮
2023/03/27
2.7K0
【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )
pthread_attr_init线程属性
线程具有属性,用pthread_attr_t表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。我们用pthread_attr_init函数对其初始化,用pthread_attr_destroy对其去除初始化。
心跳包
2020/08/31
1.9K0
线程源码分析之attr.c(基于linuxthreads2.0.1)
attr.c是线程属性管理的实现。因为linuxthreads是通过创建一个进程的方式实现线程的,所以属性中支持设置调度的优先级,调度策略等(参考操作系统的实现)。该文件没有太多内容。具体作用在分析其他文件的时候再作分析。
theanarkh
2019/10/08
6900
Can't build Qt5 (qtbase) on Windows XP (win32-msvc2005)
In a cmd.exe prompt, using msysgit, I cloned git://gitorious.org/qt/qtbase.git. Set QTDIR to that qtbase directory, added %QTDIR%\bin to PATH. Made sure sh.exe is not in the PATH. Set The problem:
用户3519280
2023/07/06
1750
Can't build Qt5 (qtbase) on Windows XP (win32-msvc2005)
使用vc(vs2008)编译Qt5.4
官方的Qt 只有vc10以上的版本 若是想vc9 只能自己编译 so 开始干 搜索资料 1)vc9不能支持webkit的编译 直接删除掉 2)有部分地方 vc9默认支持LONG转ULONG 需要自己改代码 3)需要OPENSSL 4)需要python3.4.3 5)需要activePerl开工 1。下载安装activeperl 2。下载安装python3.4.3 3。编译openssl 0.9.8k perl Configure VC-WIN32 –prefix=C:\Build-OpenSSL-VC9-32 ms\do_ms nmake -f ms\nt.mak   nmake -f ms\nt.mak install 4。开始config Qt5 一个bat搞定
用户3519280
2023/07/06
3150
【Linux探索学习】第二十九弹——线程概念:Linux线程的基本概念与线程控制详解
https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482
GG Bond1
2025/02/19
1770
【Linux探索学习】第二十九弹——线程概念:Linux线程的基本概念与线程控制详解
并发问题解密:探索多线程和锁机制
描述: pthread_create()函数在调用进程中启动一个新线程。新线程通过调用start_routine()开始执行;arg作为start_routine()的唯一参数传递。
Lion 莱恩呀
2024/09/26
3180
并发问题解密:探索多线程和锁机制
pthread_create 线程属性-多线程操作 pthread_create pthread_join
  例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等。
宜轩
2022/12/26
1.1K1
Linux线程互斥学习笔记--详细分析
    在Linux下, 线程的互斥量数据类型是pthread_mutex_t 在使用前, 要对它进行初始化:
用户6754675
2019/12/09
8430
Linux笔记(18)| 线程基础(二)
上一节里讲了线程的基本概念,和进程的关系等等。这一节来深入一些,讲一讲具体的一些知识。
飞哥
2020/11/25
6250
Linux笔记(18)| 线程基础(二)
Linux多线程编程(一)
属性对象主要包括是否绑定、是否分离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。pthread_attr_t结构的定义,定义在pthread.h中
efonfighting
2019/09/24
2K0
Linux多线程编程(一)
Posix线程 它们那一大家子事儿,要觉得好你就收藏进被窝里慢慢看 (1)
官方话就是:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
看、未来
2020/08/25
4040
Posix线程 它们那一大家子事儿,要觉得好你就收藏进被窝里慢慢看  (1)
【Linux线程】线程控制原语详细介绍
线程就是 Light weight process ,LWP,轻量级进程,在Linux环境下它仍然是进程,一个进程内部可以有多个线程,默认情况下一个进程内部有一个线程。不同的是,进程有自己的进程控制块PCB,并且拥有自己独立的地址空间;而线程虽然也有线程控制块(这样来看,如果一个进程内有多个线程,那么进程内将有多个PCB),但是它没有独立的地址空间,而是共享空间,我们可以理解为在进程的虚拟空间中除了栈都是共享的(在实际编程中,线程一般就是一个函数,函数肯定要有自己的栈来运行)。也就是说,进程和线程最大的区别在于是否共享地址空间。在Linux环境下,线程是最小的执行单位,进程是最小的资源分配单位。
mindtechnist
2024/08/08
1830
【Linux线程】线程控制原语详细介绍
多线程编程C语言版
什么是多线程,提出这个问题的时候,我还是很老实的拿出操作系统的书,按着上面的话敲下“为了减少进程切换和创建开销,提高执行效率和节省资源,我们引入了线程的概念,与进程相比较,线程是CPU调度的一个基本单位。”
DeROy
2021/11/16
3.8K0
多线程编程C语言版
Linux多线程编程小结
前一段时间由于开题的事情一直耽搁了我搞Linux的进度,搞的我之前学的东西都遗忘了,非常烦躁的说,如今抽个时间把之前所学的做个小节。文章内容主要总结于《Linux程序设计第3版》。
全栈程序员站长
2022/07/12
1.7K0
12(线程控制)
线程属性主要有: (1)线程的分离状态属性detachstate, (2)线程栈末尾的警戒缓冲区大小guardsize, (3)线程栈的最低地址statckaddr, (4)线程栈的大小stacksize。 如果对现有某个线程的终止状态不感兴趣的话,可以使用pthread_detach函数让操作系统在线程退出时候收回它所占用的资源。
提莫队长
2019/02/21
5700
Linux下多线程编程详解简介
上面的代码很简单,就是启动一个线程,然后先线程里循环打印字段字符串。我们就以这个最简单的例子来开口。
用户2929716
2018/08/23
4.4K0
线程属性设置
本文将通过一个创建n个线程的案例来展示一下线程属性的设定及使用,通常情况下,系统对于线程的创建是没有限制的,但是每一个线程都是需要一个栈空间的,每个栈空间大小也都是固定的,可通过系统命令 ulimit -a 来查看,如果线程栈空间的总数超过了一个进程可使用的虚拟内存用户空间,那么就无法再继续创建线程了。我们只是做一个小的测试,调整每个线程的栈空间大小来揭露线程属性的使用方法,并提高一个程序创建线程的数量(Notice:提高线程数量并没有什么好处,我们只是为了演示如何修改线程属性)。
我与梦想有个约会
2023/10/20
3950
线程属性设置
温故Linux后端编程(三):线程
在多处理器共享内存的架构中(如:对称多处理系统SMP),线程可以用于实现程序的并行性。历史上硬件销售商实现了各种私有版本的多线程库,使得软件开发者不得不关心它的移植性。对于UNIX系统,IEEE POSIX 1003.1标准定义了一个C语言多线程编程接口。依附于该标准的实现被称为POSIX theads 或 Pthreads。
看、未来
2021/09/18
6840
推荐阅读
相关推荐
QThread源码浅析[通俗易懂]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档