Web端H.265播放器研发解密

音视频编解码对于前端工程师是一个比较少涉足的领域,涉及到流媒体技术中的文本、图形、图像、音频和视频多种理论知识的学习,才能够应用到具体实践中,本团队在多媒体领域深耕两年多,才算是有一定产出,我们自研web播放器并支持h.265解码,在码率优化的大背景下(保持画质不变情况下,应用图像增强、roi区域检测、智能场景分类和h265编解码等多种技术能力,将码流降低50%。达到减少带宽成本,提升视频服务QoE的目的),真正做到了h265解码播放的全域覆盖。

播放器整体架构

我们播放器整体架构设计如下:

本文主要分享了我们基于WebAssembly实现H.265格式的解封装、解码和播放。

背景

H.265又称HEVC(全称High Efficiency Video Coding,高效率视频编码),是ITU-T H.264/MPEG-4 AVC标准的继任者。相比H.264,H.265拥有更高的压缩率,也就意味着同样码率(又称比特率是指每秒传送的比特(bit)数。单位为bps(Bit Per Second),比特率越高,每秒传送数据就越多,画质就越清晰),H.265的画质会更清晰,更高的压缩率就能使用更低的存储和传输成本。

  • 带宽成本:在有限带宽下H.265能传输更高质量的网络视频,理论上,H.265最高只需H.264编码的一半带宽即可传输相同质量视频。更低的带宽可以更好的降低存储及传输成本,并为未来基于短视频及直播领域更多更复杂好玩的互动玩法做铺垫。
  • 转码成本:但是当前主流浏览器均不支持H.265原生视频播放,因此通常视频生产端需要针对浏览器做一次H.264视频的转码来适配浏览器端如PC场景的播放,而增加了转码成本。如在淘宝直播中,假设以每天5万场直播计算,每场直播转码成本20元,一天就是100万的转码成本。
    为此,我们团队对浏览器端H.265视频播放的可行性及兼容性进行了一次探索,为移动端及PC端全量H.265做准备,也对浏览器端视音频处理、WebAssembly实践进行一次深入的尝试。

H.264 vs H.265

H.264是当下用的最为广泛的视频编码格式,H.265标准围绕着现有的视频编码标准H.264,保留原来的某些技术,同时对一些相关的技术加以改进。新技术使用先进的技术用以改善码流、编码质量、延时和算法复杂度之间的关系,达到最优化设置。H.265和H.264都是基于块的视频编码技术,主要的差别在于编码单元的大小以及一些编码算法细节,H.265将图像划分为“编码树单元(coding tree Unit, CTU)”,而不是像H.264那样的16×16的宏块。根据不同的编码设置,编码树单元的尺寸可以被设置为64×64或有限的32×32或16×16。一般来说区块尺寸越大,压缩效率就越好。具体的算法及相关细节这里不具体展开了,还有一些其他的压缩算法如因为H.265专利限制而生的开放编码格式如AV1等,读者可以参考其他相关文章。
h264vsh265.png

如下图,可以看到同样主观画面质量,H.265(500K)仅需H.264(800K)一半左右的带宽码率。
h264vsh265.png

浏览器现状

如下图,因为H.265专利及硬解支持情况不完善的原因,主流现代浏览器均不兼容H.265编码的视频播放(Edge新版本以插件方式支持),但是因为Apple对H.265的支持(这里作者认为这可能是一个很重要的标志,因为技术的发展很多时候不光是这个技术本身所决定的,而是很多因素共同作用的结果,商业也是其中很重要的一个因素),移动端ios safari在11.0版本以上支持原生播放。
h265comp

想要在浏览器端播放H.265视频原生的<video />标签没有办法支持,但是因为视频格式本身是连续图像画面音频的集合,参考了chromium的源码及video标签内部的实现原理,可以通过<canvas /> + Web Audio API 的结合来模拟实现一个虚拟的video标签来实现播放器功能。

demo

因为直播流时效性的缘故,发布了一个播放H.265 mp4视频(该视频地址直接在浏览器中播放只有声音而没有画面)的在线demo,读者可以有一个直观感受。
地址:https://g.alicdn.com/videox/mp4-h265/1.0.2/index.html
效果:
demo.gif

前期调研

视音频基础

因为前端领域对视频领域的涉及场景不多,一个<video />标签就可以满足大部分场景,但是经历了这几年直播和短视频的爆发,视频的需求和功能也变得越来越复杂,开发之前阅读了很多视音频领域相关的书籍和文章,在此先对视音频基础进行一个简单的介绍。

视频中我们通常说的视频的格式,比如 .mp4, .mov, .wmv, .m3u8, .flv 等等被称为container。在一个视频文件中音频、视频数据是分开存储的,使用的压缩算法也不一样。其中container作为容器主要包含了video数据、audio数据、metadata(用于检索视音频payload格式等信息)。每个格式的封装格式不一样,比如FLV格式的基本单元是Tag,而MP4格式的基本单元是Box,辅助的meta信息用于检索找到对应的原始数据。

而平时听到的H.264, H.265等视频编码标准被称为codec (COmpress and DECompress )。一个视频格式比如mp4可以使用任何标准化的压缩算法,这些信息都会被包含在一个视频文件的meta信息中来告诉播放器该用什么编解码算法来播放。

客户端播放器

一个传统的客户端播放器播放一个视频流经过了如下各个环节:

拉取数据 => 解封装 => 音视频解码 => 采样/像素数据发送到设备进行渲染。
client

对于流媒体,播放器客户端通过拉流以数据源(音视频流)为中心,进行管道式的传输。在此期间,对视频流的读取,转换,分类,复制等一系列操作处理,以封装的mp4流为例,需要对流进行解封装、解码、渲染等步骤:
stream

浏览器video标签

在探究的过程中,为了了解主流浏览器不支持H.265视频播放的原因,以及浏览器端实现播放器原理的了解,通过对Chromium浏览器官方文档及video标签实现源码的阅读,整理了一个流程图。
chromium

可以看到浏览器内部对视频流播放的实现,在经过了PipelineController等数据传输管道的处理后利用FFmpeg软解或者Gpu硬解之后交给视频设备及音频设备进行同步及渲染。其中H.265的视频因为硬解支持情况不完善,软解可能有性能风险,所以在chrome中被关闭了不支持,在chromium中可以通过参数打开。我们就依照这个思路,利用浏览器提供的接口来实现一个模拟的video标签。

设计过程

开发思路

开发思路按照从简单到复杂的过程,对任务进行拆分,来完成H.265视频点播及直播等各个场景的覆盖,以mp4短视频出发完成播放流程,再覆盖直播场景,考虑如网络抖动、内存控制等复杂因素,再针对直播m3u8等回放文件进行播放并开发视频seek、倍速等功能。

mp4播放=>flv播放=>hls播放=>加入seek、倍速等功能

可行性分析

  • 思路:在最开始进行可行性分析时,参考结合了已有工具videoconverter.js和libde265.js对H.265视频ffmpeg的编译提取了hevc文件及mp3音频文件在浏览器端进行了播放。
  • demo地址:https://sparkmorry.github.io/mse-learning/h265/
  • 表现:将720P的mp4视频进行视频和音频的分离,通过 <canvas /> 绘制图像,通过 <audio /> 标签播放音频,画面在Macbook Pro上Chrome浏览器下在23fps左右。
  • 问题:

    • 不能达到解码性能标准: 720P的视频在Macbook Pro上仅在23fps左右,而原视频是25fps,不能达到解码性能标准,无法流畅播放。
    • 无法做到音画同步: 该方案因为直接提取了hevc裸流文件,无法获取视频和音频每帧的pts时间戳,无法做到严格的音画同步。
  • 解决方案:

    • 性能:因为libde265.js是asm.js,通过对libde265.js开源库的改造,打包WebAssembly测试性能情况
    • 音画同步:参考flv.js、hls.js等开源视频库的方案,根据曾经的实践经历,js在解封装方面的性能能够完成视频流文件解封装,获取每帧视频、音频播放的pts及原始数据交给解码器进行解码再渲染。
  • 方案调整:
    1

MP4点播流播放

  • 思路:根据上一过程调整的解决方案,通过js对mp4流进行解封装,因为音频解码的复杂度不高,也先用js进行解码,仅将视频解码模块用已有的三方模块libde265并替换为wasm解决性能问题,音视频解码模块都自身维护一段缓存区,负责存储解封装模块传过来的packet数据,解决音画同步的问题。
  • 表现:通过开源libde265实现的视频解码模块,针对于720p的视频流,平均解码时间是45ms,不能满足每一帧音频播放时间间隔(40ms)。
  • 问题:视频解码性能仍然不够。
  • 解决方案:

    • 丢帧:保证了音频同步,丢掉部分非参考帧,但损失了部分体验。所以提升解码性能和改善播放策略才能有可能满足当前方案的可行性。提升解码性能和改善播放策略。
    • 提升解码性能:用解码性能更好的ffmpeg替换掉libde265。
    • 改善播放流程:因为每个requestAnimationFrame循环任务都是同步的,边解码边播放。引入用WebWorker线程。通过改善视频解码模块,解码器内部开启循环解码,当外部的视频播放设备需要播放下一帧时,直接从解码器解码完的帧缓存中读取下一帧数据。实现了worker和主线程并行执行。
  • 方案调整:

    • demo地址:https://static-assets.cyt-rain.cn/h265/index.html
    • 设计流程
      2

FLV直播流播放

  • 思路:mp4视频流畅播放,但在直播场景(如FLV视频流)中,客户端需要和服务端建立长链接,不断接收流消息,借用FFmpeg本身对流媒体的支持,对视频数据进行解封装及解码。
  • 表现:无法编译FFmpeg网络库,TCP无法建立连接。
  • 问题:
    无法编译FFmpeg网络库:TCP建立连接创建Socket时报错,Emscripten工具无法编译TCP连接相关配置

codec不支持:FLV官方协议不支持H.265。

  • 解决方案:

    • 无法编译FFmpeg网络库:主线程利用fetch方法进行拉流,放到FFmpeg自定义缓冲区进行解封装及解码。因为直播流长时间播放需要不停的开辟、释放内存空间,采用环形的数据缓冲区。
    • FLV官方协议不支持H.265:对FFmpeg及编码端对H.265进行扩展,因为FFmpeg内部数据结构嵌套较深,替换js解封装函数直接用FFmpeg的解封装函数。
  • 方案调整:

    • 设计流程
      3

当前方案

播放流程

current

  1. 因为FFmpeg支持多种格式解封装,只需要在在主线程中通过浏览器API(通常是fetch方法)拉取原始流数据并放到缓存中,等初始缓存到一个阈值时开启Worker进行解封装及解码;
  2. 在子线程(Worker)中通过主线程fetch方法触发的数据回调接收数据存入环形缓冲区(内存环)中;
  3. 子线程将读取到的音频帧输送到主线程中,通过Web Audio API缓存音频数据,根据已解码的视频帧缓存队列循环解码保证缓存中一直缓存10帧rgba图像数据;
  4. 主线程中canvas根据音频播放回调的pts消费并渲染视频图像;
  5. 循环以上操作直到fetch接口返回流已结束。

解码器编译

通过Emscripten工具可以把C语言编写的FFmpeg库编译成wasm并在浏览器中应用到视音频解码中。
我们的视频解码场景和通常的播放器一样,通过依赖FFmpeg的通用接口来实现解封装和解码的工作。先通过emscripten编译ffmpeg库,再通过静态库的方式依赖到解封装和解码入口程序中。
compile

测试表现

性能测试

测试视频

因为flv直播视频受时效性影响较大,拿720P高清的H.265 mp4视频作为稳定输入测试

  • 地址:https://gw.alicdn.com/bao/uploaded/LB1l2iXISzqK1RjSZFjXXblCFXa.mp4?file=LB1l2iXISzqK1RjSZFjXXblCFXa.mp4
  • 视频参数:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'https://gw.alicdn.com/bao/uploaded/LB1l2iXISzqK1RjSZFjXXblCFXa.mp4?file=LB1l2iXISzqK1RjSZFjXXblCFXa.mp4':Metadata:major_brand     : isomminor_version   : 512compatible_brands: isomiso2mp41encoder         : www.aliyun.com - Media TranscodingDuration: 00:01:00.10, start: 0.000000, bitrate: 907 kb/sStream #0:0(und): Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv, bt709, progressive), 1280x720, 854 kb/s, 25 fps, 25 tbr, 12800 tbn, 25 tbc (default)Metadata:handler_name    : VideoHandlerStream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 48 kb/s (default)Metadata:handler_name    : SoundHandler

测试机器

  • lenovo ThinkPad T430

    • CPU: Intel(R) Core(TM) i5-3230M CPU@2.60GHz x64处理器
    • 内存: 8 GB
    • 系统: windows 10
  • MacBook Pro (Retina, 15-inch, Mid 2015)

    • CPU: 2.2 GHz Intel Core i7
    • 内存: 16 GB
    • 系统: macOS 10.14.2

性能情况

  • MBP下表现
decoder.wasm大小decoder.js大小平均每帧解码时长内存占用cpu占用
1.4M168K26.79ms27M17~25%
  • 针对两个pc笔记本进行了测试,平均每帧解码(包含yuv420转rgba)时长在各个浏览器的表现情况如下:
    注:此处Native(原生)表示针对mac系统原生编译的FFmpeg作为依赖的解码器(相对不考虑具体如x86、arm等计算机架构的WebAssembly的跨平台方案而言)
设备ChromeSafariFireFoxEdgeNative
MacOS(i7)26.79ms22.19ms24.77ms-5.08ms
windows(i5)33.51ms-36.74ms86.72ms未测试

意味着最高能提供720P高清视频如下帧率视频流畅播放的能力:

设备ChromeSafariFireFoxEdge视频基准Native
MacOS(i7)37fps45fps40fps-25fps196fps
windows(i5)30fps-27fps12fps25fps未测试

可以看到这两台机器中,在非高速运动等普通的如电商场景25fps帧率的高清720p视频已经能达到生产环境的标准,但是距离原生的速度还有一定距离。

浏览器兼容性

主要用到了WebAssembly及WebWorker的支持,实际测试中主流浏览器Chrome、Safari、Firefox、Edge均能通过兼容性测试。

  • WebAssembly
    wasm
  • WebWorker
    worker

TODO

当前的技术方案已经能在大部分机器的主流浏览器上流畅的播放720P的高清直播流,但是在Edge浏览器及性能稍差的机器上还是存在高清视频解码性能不能满足流畅播放的风险,针对WebAssembly达到native速度的目标还有一定距离,尤其是汇编并行计算的支持,在视音频及大规模数据处理中是很常见的性能优化策略,作者整理了几个优化的方向,在未来还有更多探索的空间:

  • 汇编
    FFmpeg中解码有较多利用汇编进行并行计算的优化,但是汇编指令是cpu specific的(比如x86指令和arm指令),而wasm是跨平台的基于栈的虚拟机。Emscripten不支持汇编的编译,考虑用clang等llvm前端将FFmpeg的.c和汇编.asm文件编译成LLVM IR(LLVM Intermediate Representation),然后通过fastcomp或者其他后端来编译测试。
  • 硬解
    FFmpeg3.3以上开始支持自动硬解探测,支持的硬件设备根据不同操作系统及硬件会有不同的支持,具体参考:https://trac.ffmpeg.org/wiki/HWAccelIntro 。因为wasm是跨平台的虚拟指令集,支持程度还要待进一步探究。
  • 多线程
    FFmpeg内部解码有多线程来提高解码性能,通过pthread可以支持跨平台的多线程支持的,但是如果不支持共享内存,则线程之间的数据传输会有很多性能消耗(深拷贝或者Transfered Object)。浏览器端共享内存通过SharedArrayBuffer来实现,因为有安全隐患,大部分主流浏览器关闭了SharedArrayBuffer、Chrome67+开始恢复。考虑到兼容性多线程的支持还要再进行尝试。
  • WebGL渲染
    解码平均时长中有4ms左右(15%)在yuv转rgba上,通过WebGL可以用gpu加速图像的计算,但是同时与WebGL的数据交换又会产生一定的性能损耗,需要再测试查看性能结果

未来展望

通过H.265视频播放将开源视音频库FFmpeg的能力及WebAssembly性能的优势在浏览器端视音频处理上有了一次深入的尝试。视频作为一种多媒体形式,相比现有的文字、图像、音频都能有更生动及更丰富信息的表现。尤其经过了直播和短视频的爆发增长后,成为了一种基础的多媒体形式,也是网络及移动端手机性能等技术发展的体现。未来随着5G及更高性能的硬件设备的发展会被更广泛的应用到各个领域。浏览器在这场视频革命中也是不可或缺的一个环节,通过这次的探索,为未来浏览器端扩展视音频处理的通用能力提供了想象的空间,同时也在浏览器端通过WebAssembly向native性能及能力靠近的路上做了一个落地的尝试,虽然从测试情况看现在的表现还不如native,但是随着标准及技术的演进,为未来对性能要求比较高的图形图像及人工智能等相关方向在浏览器端处理一定会渐渐被广泛的应用起来,比如如下几个方向:

  • 扩展浏览器端视频播放能力
    借助FFmpeg强大的编解码能力,除了H.265视频的播放,未来还可以在浏览器端兼容各种格式及编码类型的视频播放。如不同的编码格式AV1、不同的容器格式mov格式等等。
  • 扩展浏览器端视音频处理能力
    借助FFmpeg及其他语言框架的现有能力,还可以在视音频领域做更多复杂的操作如视频滤镜、视频剪切、视频格式转换等功能,减少网络传输及存储的成本。
  • 基于WebAssembly的高性能web应用
    借助WebAssembly的跨平台优势,可以将传统的其他语言的开源框架如图形相关开源库OpenGL、SDL等的能力移植到浏览器上来。借助性能上的优势也可以将传统的图像、3D等运算能力要求较高的应用扩展到浏览器端。

参考

  • Chromium媒体元素源码: https://github.com/chromium/chromium/tree/master/media
  • WebAssembly: https://webassembly.org/
  • 优秀的开源视音频处理框架FFmpeg: https://www.ffmpeg.org/
  • 基于LLVM编译的WebAssembly打包工具集Emscripten:https://emscripten.org/index.html
  • 基于WebAssembly的ogg播放器:https://github.com/brion/ogv.js
  • 基于FFmpeg的简单播放器:https://github.com/leixiaohua1020/simplest_ffmpeg_player

后言

本文介绍了我们在Web端H.265播放器上研发的过程和进展,后续还有很多继续优化和深入的点。对相关知识感兴趣的同学欢迎沟通交流,附上我们前端团队的介绍:

淘宝技术部内容与开放平台前端团队是淘系核心的商业变革阵地,相对于横向资源前端团队,我们更深入在内容电商、音视频技术领域,探寻创新商业模式及业界领先技术。

本团队目前正火热招聘20届优秀毕业生,欢迎有志之士加入!
img

或者直接联系团队负责人: 灵玉 lingyu.csh@taobao.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/536647.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

拳击 武术java父类,拳击是一种很有力量的武术类型

原标题&#xff1a;拳击是一种很有力量的武术类型拳击是一种很有力量的武术类型&#xff0c;拳击比赛策略有很多&#xff0c;围绳技术是其中之一。那么拳击比赛策略技巧有哪些呢&#xff1f;下面养生之道网为您解析拳击比赛策略技巧有哪些&#xff0c;看看吧。1、当拳手靠在围绳…

kaka 1.0.0 重磅发布,服务于后端的事件领域模型框架。

百度智能云 云生态狂欢季 热门云产品1折起>>> kaka 1.0.0正式发布了&#xff0c;从三个月前的kaka-notice-lib 1.0.0的发布&#xff0c;经过多次研磨&#xff0c;终于迎来了本次重大更新。 kaka是一款服务于java后端的事件领域模型框架&#xff0c;主要目的为解耦业…

如何把WAV格式音频转换为MP3格式

WAV为微软公司&#xff08;Microsoft)开发的一种声音文件格式&#xff0c;它符合RIFF(Resource Interchange File Format)文件规范&#xff0c;用于保存Windows平台的音频信息资源&#xff0c;被Windows平台及其应用程序所广泛支持&#xff0c;因此在声音文件质量和CD相差无几&…

恶意软件盯上了加密货币,两家以色列公司受到攻击

近日&#xff0c;网络安全公司Palo Alto Networks威胁研究部门Unit 42发博称&#xff0c;已确认Cardinal RAT自2017年4月起对两家从事外汇和加密交易软件开发的以色列金融科技公司发起过攻击。 Cardinal RAT是可远程访问特洛伊木马&#xff08;RAT&#xff09;&#xff0c;攻击…

php 自定义打印模板下载,PHP – 创建自定义模板系统?

我已经在这里搜索过,令人惊讶的是我找不到答案.我发现了一个类似的线程,但没有真正的解决方案.复杂的部分是循环,如果我不需要循环我可以只是做一个常规替换.所以,我有一个带有一些标记的.html文件,如下所示&#xff1a;{{startloop}}{{imgname}}{{endLoop}}我想要做的是用其他…

腾讯财报中“最大秘密”:2018云收入91亿元,交首份TO B答卷

腾讯财报中“最大秘密”云业务收入又一次被公开了&#xff1a;2018年&#xff0c;腾讯云收入91亿元&#xff0c;增长100%。 3月21日&#xff0c;腾讯发布2018年Q4及全年财报&#xff0c;2018全年收入3126.94亿元同比增长32%&#xff0c;净利润(Non-GAAP)774.69亿元。而被列进“…

根据坐标如何在matlab中l连成曲线,matlab中,如何将两条曲线画在一个坐标系里,plot(x1,x2,y1,y2)还是怎样...

matlab中&#xff0c;如何将两条曲线画在一个坐标系里&#xff0c;plot(x1,x2,y1,y2)还是怎样以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;matlab中&#xff0c;如何将两条曲线画在一个坐…

java已被弱化签名,高效Java第四十条建议:谨慎设计方法签名

作用有助于设计易于学习和使用的API。如何做——谨慎地选择方法的名称1.选择易于理解的&#xff0c;并且与同一个包中的其他名称风格一致的名称。2.选择与大众认可的名称相一致的名称。如何做——不要过于追求提供便利的方法每个方法都应该尽其所能。方法太多会使类难以学习、使…

phpexcel.php linux,phpexcel在linux系统报错如何解决

最近有个tp3.2的项目迁移到linux系统上了&#xff0c;突然有天发现原本在win server 2008上运行没问题的excel导出功能在新的系统上不能使用了。报错如下&#xff1a;说是1762行有问题&#xff0c;找到这个文件的代码看看&#xff1a;/*** Get an instance of this class** acc…

asp.net core系列 48 Identity 身份模型自定义

一.概述 ASP.NET Core Identity提供了一个框架&#xff0c;用于管理和存储在 ASP.NET Core 应用中的用户帐户。 Identity添加到项目时单个用户帐户选择作为身份验证机制。 默认情况下&#xff0c;Identity可以使用的 Entity Framework (EF) Core 数据模型。 本文介绍如何自定义…

oracle中创建游标,oracle 存储过程创建游标

Oracle与Sql Server差异点详解1、create函数或存储过程异同点Oracle 创建函数或存储过程一般是 create or replace ……SQL SERVER 则是在创建之前加一条语句&#xff0c;先判断是否已经存在&#xff0c;如果存在删除已有的函数或存储过程。函数语句&#xff1a;if exists (sel…

hosts文件不起作用

突然发现电脑的hosts文件不起作用了。之前用的狠正常&#xff0c;近期也没有修改过。首先排除什么格式、DNS、注册表之类的问题。最终解决办法&#xff08;权限问题&#xff1a;有问题的hosts文件图标上有个锁&#xff09;&#xff1a;1.C:\Windows\System32\drivers\etc下复制…

oracle面临的挑战,未来数据库管理员面临的三大挑战

原标题&#xff1a;未来数据库管理员面临的三大挑战前言今天的数据库管理员面临着三大挑战&#xff1a;工作重心向以应用程序为中心转移、支持多个数据库平台的需求、在云端以及在本地管理数据库性能的责任不断扩大。为了在今天和未来都能站稳脚跟&#xff0c;数据库管理员需要…

打造汽车“安卓平台”,大众或亲手干掉传统汽车产业

干掉传统汽车产业的&#xff0c;很可能是大众&#xff0c;而不是特斯拉。 于无声处听惊雷。 2019年的日内瓦车展&#xff0c;看起来并没有传出太大的新闻。汽车世界的目光&#xff0c;依然被特斯拉的喧嚣所吸引。 然而&#xff0c;大众汽车展台上发生的一件看似不起眼的小事情&…

从 SPA 到 PWA:Web App的下一站在哪?

从AJAX&#xff08;Asynchronous JavaScript XML&#xff0c;异步JavaScript和XML&#xff09;开始&#xff0c; 尤其是 AngularJS 推出之后&#xff0c;SPA&#xff08;Single Page App&#xff0c;单页应用&#xff09;已经成为前端 App 的必选方案。 SPA 可以在客户端提供完…

Unable to resolve dependency问题解决

Unable to resolve dependency 是一个让我头疼的问题 之前总是阴差阳错调试好 但是也没有总结出来方法 但是今天找到了 方法来源 https://jingyan.baidu.com/article/19192ad8c489dfe53e5707ee.html 原因就是用户的gradle.properties 设置了代理&#xff0c;将文件内的代理注释…

计数排序与桶排序python实现

计数排序与桶排序python实现 计数排序 计数排序原理&#xff1a; 找到给定序列的最小值与最大值 创建一个长度为最大值-最小值1的数组&#xff0c;初始化都为0 然后遍历原序列&#xff0c;并为数组中索引为当前值&#xff0d;最小值的值&#xff0b;&#xff11; 此时数组中…

JVM快速调优手册02:常见的垃圾收集器

2019独角兽企业重金招聘Python工程师标准>>> 如果说收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回收的具体实现。 Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定&#xff0c;因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可…

linux运维平台工具,Linux运维自动化工具 Kickstart

简介&#xff1a;批量安装操作系统工具之 Kickstart &#xff0c;RedHat 早前推出的产品( 不多说了&#xff0c;现在都玩 Cobbler 啦&#xff0c;见 http://www.linuxidc.com/Linux/2016-04/129977.htm )。测试环境&#xff1a;CentOS 6.6 x86_64 minimal一、安装软件包shell &…

PostgreSQL 并行查询概述

2019独角兽企业重金招聘Python工程师标准>>> PostgreSQL从9.6版本开始加入并行查询&#xff0c;并在PostgreSQL10和PostgreSQL11分别做了大量加强工作。下面从&#xff1a; 何时启用并行查询功能并行查询是如何工作的worker进程数量越多&#xff0c;查询性能越高吗三…