Pinterest:Android系统上的视频管理

Stella981
• 阅读 462

Pinterest通过在Android应用中添加适当的视频管理,在为用户提供更加流畅的视频体验的同时,尽可能的为开发人员提供易于使用的视频组件,简化其工作流程。 本文来自Pinterest工程博客。

文 / Grey Skold

译 / 屈健宁

原文

https://medium.com/pinterest-engineering/managing-videos-on-android-f59da9601d5f

2016年Pinterest安卓应用上发布的视频模块,其目标是使得应用能够提供无缝的视频体验。包括支持在每个屏幕上同时播放多个视频,并且通过滚动出屏幕自动暂停播放的方式来动态地控制视频的播放状态以及同时播放的视频数量。

很快我们发现其实需要应对的技术挑战有很多,例如:

  • 管理当前所有可用视频的播放状态

  • 了解视频在屏幕上的可见率

  • 为我们的开发人员提供易于使用的视频组件

随着工作的进行,我们逐渐调整视频架构来满足这些需求,下面我们将在最新的视频模块中深入探讨如何应对这些挑战。

视频管理

从更高的层次上来看,我们需要构建一个组件,这个组件需要感知屏幕上所有可用的视频实例(即视图)以及其相关的surfaces(即视频片段)。管理surfaces对于监控应用于surfaces的子对象的生命周期状态(即onStart()等)至关重要,并且避免在使用者层上添加过多代码来将最新状态更改应用到视图。

为了跟踪这些关键的生命周期事件,Android框架向我们提供了屏幕显示内容的当前状态以及视觉上影响我们应用程序的任何更改。我们监测的关键生命周期事件是UI附件调用(例如onAttachedToWindow())以及主机屏幕何时更改其显示状态(例如onPause()等)。

使用这些回调方法,我们尝试记录已提供有效视频URL的所有视频。这将为我们提供当前范围内可用的视频的初始列表。

在视频框架的第一个迭代中,我们依靠客户端代码本身调用这些调用,但是我们发现这是不可扩展的。因为它在构建视频功能时增加了更多的复杂性。取而代之的方法是,我们通过构建需要传入基础视频组件的方法,提取了在VideoManager之后注册视频的回调方法。从那里,VideoManager将在幕后进行适当的计算。由于它现在才可以“开箱即用”地工作,因此消除了观众对视频记录过程已经具有预定义知识的需求。

改进前

     // FooBarFragment.class for FooBar feature
 
     
     
     
 
     
     
     override fun onResume() {
 
     
     
          
 
     
     
     super.onResume()
 
     
     
          
 
     
     
     // Required by consumers to implement
 
     
     
          videoView?.apply {
 
     
     
               viewability = Viewability.
 
     
     
     FullyVisible          onActivate()          onViewCompletelyVisible()     }}override fun onPause() {
 
     
     
          
 
     
     
     // Required by consumers to implement
 
     
     
          videoView?.apply {
 
     
     
               viewability = Viewability.
 
     
     
     NotVisible          onDeactivate()     }     super.onPause()}

    
    
    

改进后

     // BaseFragment.class implemented by all screens
 
     
     
     
 
     
     
     override fun onResume() {
 
     
     
          
 
     
     
     super.onResume()
 
     
     
          videoManager.onResume(
 
     
     
     this)
 
     
     
     }
 
     
     
     
 
     
     
     override fun onPause() {
 
     
     
          videoManager.onPause(
 
     
     
     this)
 
     
     
          
 
     
     
     super.onPause()
 
     
     
     }
 
     
     
     
 
     
     
     // VideoManager.class internally
 
     
     
     
 
     
     
     override fun onResume(videoSurface: VideoViewSurface) {
 
     
     
          videoSurface.videoViews.forEach {
 
     
     
               registerVideo(it)
 
     
     
          }
 
     
     
     }
 
     
     
     
 
     
     
     override fun onPause(videoSurface: VideoViewSurface) {
 
     
     
          videoSurface.videoViews.forEach {
 
     
     
               unregisterVideo(it)
 
     
     
          }
 
     
     
     }
 
     
     
     

    
    
    

保留这个视频列表让我们可以根据应用程序的当前可见性来动态地设置播放状态。同时这个方法还提供了基于在视频记录时传递的某些元数据属性动态更改之类其他功能的灵活性。

例如,我们可能希望所有视频广告都自动播放,但仅限于在同一片段上自动播放1个有机视频(即创作者生成的内容)。通过检查在单个视频上记录的元数据,我们可以将这些限制应用于UI层。

我们还提取了所有Pinterest特定的分析代码,用以来聚焦在视频管理器(管理和播放视频)功能上,同时让这个管理组件和应用程序之间保持独立。

计算可视性

可视性定义为在屏幕上显示的UI组件的可见区域的百分比。此度量对于我们了解当前显示给用户的内容至关重要。有了这些信息,我们就能为合作伙伴收集有关其内容参与度的信息。

在常见情况下,由于VideoManager保留对所有活动视频的引用,因此我们可以跟踪视图的确切坐标(即getLocationInWindow())和设备的屏幕尺寸(以像素为单位)(请参见DisplayMetrics),以推断其在屏幕上的可见性。

我们还通过以下方式处理重叠的UI组件:

  • 向消费者提供包括一系列``障碍物’'视图的选项,这些视图可能会覆盖我们的基础视频(例如工具栏,浮动按钮等)

  • 显示弹出窗口的回调(即onWindowFocusChanged())屏幕滚动组件或UI组件不在屏幕上(请参阅RecyclerView监听器)

  • 屏幕上显示视频表面时的其他回调(即onResume()等)

为开发人员打造的内容

虽然我们希望减少开发人员面临的视频管理复杂性,但是这其中最大的困难就是采用新的视频界面。因此,我们都抽象出了视频设置的复杂性以及Google PlayerView提供的UI组件的使用:

改进前

     // FooBar video feature, requires custom FooBarVideoView.class of 100+ lines
 
     
     
     object : FooBarVideoView(
 
     
     
          context,     
 
     
     
     // application context
 
     
     
          analytics,   
 
     
     
     // Analytics object
 
     
     
          url,         
 
     
     
     // video url
 
     
     
          uid,         
 
     
     
     // unique ID
 
     
     
          
 
     
     
     false        
 
     
     
     // isAd flag
 
     
     
     ) {
 
     
     
          
 
     
     
     // configuration flag for custom setup (mute, autoplay, controller, etc.)
 
     
     
          override val videoConfiguration = VideoConfiguration.FOO_BAR
 
     
     
     }.apply {
 
     
     
          shouldLoop = 
 
     
     
     true
 
     
     
          videoAspectRatio = 
 
     
     
     aspectRatio     render(videoMetaData) // loads video, videoMetaData contains: url, isAd, uid}

    
    
    

改进后

     // Foobar video feature, no custom class required just set flags
 
     
     
     PinterestVideoView(context).apply {
 
     
     
          
 
     
     
     // Optional params for setup/customization
 
     
     
          
 
     
     
     this.analytics = pinterestAnalytics
 
     
     
          
 
     
     
     this.mute = 
 
     
     
     false
 
     
     
          
 
     
     
     this.autoPlay = 
 
     
     
     true
 
     
     
          
 
     
     
     this.alwaysAutoplay = 
 
     
     
     true
 
     
     
          
 
     
     
     this.alwaysPlay = 
 
     
     
     true
 
     
     
          
 
     
     
     this.showMute = 
 
     
     
     true
 
     
     
          
 
     
     
     this.looping = 
 
     
     
     true
 
     
     
          
 
     
     
     this.bufferingRule = SHOW_BUFFERING_ALWAYS
 
     
     
     }.apply {
 
     
     
          render(videoMetaData) 
 
     
     
     // loads video, videoMetaData contains: url, isAd, uid
 
     
     
     }
 
     
     
     

    
    
    

视频基础架构的另一个复杂性是实际的VideoManager体系结构本身。在我们的重写中,我们将大多数旧组件合并为仅支持正常运行的VideoManager的核心部分。

改进前

Pinterest:Android系统上的视频管理

改进后

Pinterest:Android系统上的视频管理

我们新的VideoManager体系结构为事件和组件之间的相互关系提供了清晰的层次结构。这不仅在纸面上看起来不错,而且仅重构一项就删除了约4,500行代码(不到原始实现大小的1/3)

展望

建立适当的“视频管理”是一个漫长而艰巨的过程,但是多年来,我们已经构建了一些真正经过改进的东西,以帮助简化我们的开发流程和Pinner体验。将来,我们希望开源我们的工作,以便其他开发人员可以为正在进行的处理动态视频回放做出贡献。我们将继续迭代我们的视频客户端架构,以应对新的挑战,以期为Pinners和开发人员提供令人愉悦的视频体验。

LiveVideoStackCon 2019深圳讲师招募

12月13-14日,LiveVideoStackCon首次来到深圳,将全球前沿多媒体技术实践与深圳本地产业结合,触发技术与商业灵感。欢迎将你的技术实践、踩坑与填坑经历、技术与商业创业的思考分享出来。请将个人资料和话题信息邮件到 speaker@livevideostack.com 或点击【阅读原文】了解成为LiveVideoStackCon讲师的权益与义务,我们会在48小时内回复。

LiveVideoStack 秋季招聘

LiveVideoStack正在招募编辑/记者/运营,与全球顶尖多媒体技术专家和LiveVideoStack年轻的伙伴一起,推动多媒体技术生态发展。同时,也欢迎你利用业余时间、远程参与内容生产。了解岗位信息请在BOSS直聘上搜索“LiveVideoStack”,或通过微信“Tony_Bao_”与主编包研交流。

Pinterest:Android系统上的视频管理

本文分享自微信公众号 - LiveVideoStack(livevideostack)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
Unity横屏
Android下发现Unity里面的Player设置,并不能完全有效,比如打开了自动旋转,启动的时候还是会横屏,修改XML添加以下代码<applicationandroid:icon"@drawable/ic\_launcher"                    android:label"@string/app\_name"
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这