作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Krzysztof Ożóg的个人资料图片

Krzysztof Ożóg

Krzysztof是一名熟练的Symfony开发人员,对Symfony 2有很好的了解, Symfony 3, PHP, and OOP coding.

Years of Experience

16

Share

如今,任何web应用的成功和普及都高度依赖于它的性能, flexibility, and ease of use.

尤其是在今天的多动症世界里, 如果页面加载时间过长,用户很快就会对应用失去耐心. 对于需要支持视频处理的web应用程序(这本身就是计算和I/ o密集型的),这一挑战尤为严峻. 尽管如此,用户的要求越来越高,他们希望自己的视频质量高 and 快速加载,即使在智能手机或平板电脑上运行.

用户也在逐渐失去对无法在他们喜欢的浏览器或设备上运行的网络应用的容忍度, 或者不支持加载或导出所需的数据格式. 因此,需要支持的视频格式的多样性也使得将视频支持整合到web应用程序中尤其具有挑战性.

这篇文章描述了我如何有效地利用开源技术和基于云的服务,将视频功能整合到一个基于php的web应用程序中.

使用Wowza和Amazon Elastic Transcoder在PHP中处理在线视频

Use Case

我所在的团队需要开发一个类似youtube的网站, 注册用户可以在哪里上传和分享他们的视频.

该系统需要允许注册用户以各种支持的格式上传视频,然后将其转换为通用格式(MP4)。. 我们还需要生成一组缩略图和图像拼贴,用于在视频播放器中显示视频进度条上的帧.

由于客户端要求阻止我们使用任何可用的CDN或转码api,事情变得更加复杂, 所以我们需要从头开始开发我们的解决方案.

Video Upload

因为上传过程本身并不需要特定于视频(我们只需要一个易于使用的文件上传功能)。, 使用现有的开源解决方案比开发我们自己的解决方案更有意义. We selected jQuery-File-Upload, primarily because it supported two features that were essential in our case; namely, 上传进度条和分块上传.

Chunked uploading 使我们能够允许用户上传几乎任何大小的视频文件(特别是支持高清分辨率的视频文件). With this approach, 该文件在前端被分成多个“块”,对每个数据块(以及每个块的元数据)调用上传操作, 例如块数和总文件大小). 然后在后端重新组装完整的视频文件. Incidentally, 在元数据中包含块号被证明是特别重要的,因为一些浏览器(比如Mobile Safari)倾向于以随机顺序传输块.

Online Video Processing

视频处理可以像捕捉静止图像一样简单, 或者可以涉及更复杂的操作,如图像增强, stabilizing the video stream, and so on. In our case, 唯一的视频处理要求是:(a)提取视频编解码器和其他关键元数据;(b)生成一组缩略图和图像拼贴图(用于在视频播放器中显示视频进度条上的帧).

FFmpeg – a widely-used, freely-distributed, 开源库——在满足这些需求方面非常有帮助. FFmpeg provides a complete, 跨平台的录音解决方案, converting, 以及流媒体音频和视频文件. 它也可以用来转换视频和做简单的编辑(如.g.,修剪,切割,添加水印等.).

For our purposes, 我们能够使用FFmpeg将视频分成十个部分, 然后为每个部分捕获缩略图,以提供所需的功能.

但是,不幸的是,没有针对FFmpeg库的PHP语言绑定. As a result, 从PHP中利用FFmpeg的唯一方法是使用系统命令从命令行调用二进制文件. 在PHP中基本上有两种使用FFmpeg的方法:

  • libav. Libav是一个自由软件项目, forked from FFmpeg in 2011,生成处理多媒体数据的库和程序. 例如,在Ubuntu上,这可以用命令安装 安装libav-tools. libav命令与FFmpeg和 avconv. PHP需要有命令行访问 ffmpeg/avconv 以编程方式使用它.
  • PHP-FFMpeg. PHP-FFMpeg是一个面向对象的PHP驱动程序,用于FFMpeg二进制文件. 它可以通过简单地执行来访问 Composer更新“php-ffmpeg/php-ffmpeg”.

我们使用PHP-FFMpeg,因为它提供了对我们感兴趣的FFmpeg功能的简单访问. For example, the FFProbe 类使您能够接收有关编解码器或特定视频文件长度的信息,如下所示:

$ffprobe = FFMpeg\ ffprobe::create();
$ffprobe
    ->format('/path/to/video/mp4') // extracts file informations
    ->get('duration'); 

FFmpeg也可以很容易地保存任何视频帧:

$ffmpeg = ffmpeg \ ffmpeg::create();
$video = $ffmpeg->open('video.mpg');
$video
    ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10))
    ->save('frame.jpg');

可以获得更详细的示例代码 here.

One note of caution: Due to some patent laws, 不是所有的编解码器都可以用FFmpeg处理,有些格式不被正确(或完全)支持. 比如,我记得几年前,我和 .3gp 格式,当支持功能手机是必须的.

Queuing

在获得视频的编解码器和其他元数据之后, 我们将视频推送到FIFO(先进先出)转换队列. 这个队列是使用一个简单的cron脚本实现的,每次运行时选择给定数量的未处理视频,并将它们传递给转换实用程序(示例源代码可用) here).

转换实用程序调用FFMpeg来执行转换,并将每个视频标记为已处理.

我们还开发了一个简单的等待时间估计机制, 哪个计算转换1分钟视频的平均时间. Using this average, 我们能够计算并显示用户在视频上传完成后的估计剩余处理时间, 根据还有多少分钟的视频需要处理.

Video Format Conversion

某些普遍认可的静态图像格式(如JPEG和GIF)已经出现,基本上所有设备和图像处理软件都支持这些格式. 虽然有些视频格式比其他格式更常见, 目前还没有这种普遍支持的视频格式出现.

In our case, 除了需要将各种格式转换为单一的通用格式(MPEG-4)之外,, 我们需要对转换后的视频进行优化,以便流式传输到移动设备.

对于视频格式转换(至少对于我们的短期需求),使用基于云的 Amazon Elastic Transcoder 这是最好的选择吗. 除了它的一般易用性, 转码器服务负责优化和所有编码设置. Fortunately, an AWS SDK for PHP ,这简化了从PHP代码调用服务的过程.

Note: 如果你想快速启动和运行,使用Amazon Elastic Transcoder等基于云的服务是很好的选择. However, 请记住,这个选项对您的客户来说可能会很昂贵, 特别是如果他们的商业模式可能需要大量使用大型视频. 另一个需要考虑的因素是,你不应该假设你的客户的视频或商业模式将与服务条款兼容.

亚马逊使用它的基本存储和计算元素, S3 (Simple Storage Service) and EC2 (Elastic Compute Cloud) – combined with Auto Scaling and SNS(简易通知服务) -提供几乎即时扩展和缩减的能力.

Installation of aws-sdk 很简单,因为Amazon维护了一个 Composer-包的可安装版本. Simply add ”aws/aws-sdk-php": "2.*" to your composer.json file and do a composer update.

Obviously, 访问Amazon Elastic Transcoder需要一个Amazon帐户, 因此,如果您(或您的客户)还没有这样的设置,您还需要设置.

我们使用Amazon Elastic Transcoder服务时,首先需要将视频文件上传到S3上合适的存储桶. 然后,我们让转码器工作负责解码并生成缩略图, on completion, 向指定地址发送HTTP请求. 这确实需要在AWS面板中进行一些配置, 但它非常简单,亚马逊提供了很好的文档来说明如何做到这一点.

Feel free to make use of our transcoder bundle,这有助于简化 Symfony 2. 它包括一个用法描述,并提供了一个控制器,用于快速实现由Amazon发送的通知服务,以收集有关已处理视频的信息. A usage example is available here.

此外,还提供了一个处理Amazon通知的示例控制器 here 它还实现了订阅地址的确认. 服务将首先发布要访问的URL,以确认这是有效的通知接收器. 然后真正需要做的就是把视频标记为处理过的. 从那时起,我们就可以使用存储在云端的转码视频了.

Streaming

视频流是一种需要高性能的功能:用户对不间断流的期望很高,对延迟的容忍度极低. 由于需要同时实时地将视频流传输到多个客户端,这一挑战往往会加剧.

In our case, 我们需要支持每个用户能够创建他或她自己的视频频道并开始广播. 我们的解决方案由三个部分组成:

  • Dashboard. 作为流媒体仪表盘的应用程序,提供提供视频服务的能力.
  • Viewer. 消费和显示视频流的视频客户端.
  • Streaming Engine. 基于云的视频流服务.

此外,视频点播(VOD)技术仍在不断发展, 我们面临的另一个问题是摄像头访问不太受支持,只能提供P2P连接. 此外,我们的目标是为多个并发用户提供在线广播. Furthermore, support for the getUserMedia/Stream API(以前设想为 元素)在现代浏览器中还不一致. Based on these factors, 我决定使用Flash技术,因为这是唯一合理的选择. 因此,这两个应用程序(Dashboard和Viewer)都使用 Flex and ActionScript.

对于流引擎,我们使用 Wowza. 尽管还有其他非商业的解决方案(例如 Red5, 它的市场定位基本上是Wowza的替代品), 在我们的案例中,商业产品支持是一个重要因素. Also, 至少在我们建立这个系统的时候是这样, Wowza提供了更好的文档,这是一个额外的优势. (注意,你可以免费使用Wowza的试用版30天,还有开发者试用版,你可以使用最多180天. But there are some limitations; streaming can only work for two clients and there is limit on the maximum number of connections.)

Wowza Streaming Engine

我们使用了Wowza提供的LiveStream应用程序. To configure it, leave applications/app_name empty and in conf/app_name copy the Application.xml file from the conf catalogue. 编辑该文件以配置 section as follows:


  live
  ${com.wowza.wms.context.VHostConfigHome}/content
  ${com.wowza.wms.context.VHostConfigHome}/keys
  
  

The key parameter is live 它定义了这将是来自实时视频馈送的流(例如.g., a camera). 注意,在编辑并保存这个文件之后,您需要重新启动Wowza.

Flash (Flex/ActionScript)应用程序

Flash提供了一个完全集成的系统,可以将摄像头和麦克风连接到Wowza流媒体服务器. 如果你有以下方面的经验,这一点特别有用 ActionScript is limited.

整个应用程序本质上是基于以下对象之间的交互:

  • NetConnection. The NetConnection 类在客户机和服务器之间创建双向连接. 客户端可以是Flash Player或AIR应用程序. 服务器可以是web服务器, Flash Media Server, 安装了Flash Remoting的应用服务器, 或Adobe Stratus服务.
  • Camera. The Camera 类用于从客户端系统或设备摄像机捕获视频.
  • Microphone. The Microphone 类用于监视或捕获来自麦克风的音频.
  • NetStream. The NetStream 类通过NetConnection打开单向流通道.

First, 我们使用NetConnection实例连接到Wowza流服务器,然后附加事件监听器,监听网络连接状态的变化:

nc = new NetConnection();
nc.连接(serverAddress: string);
nc.addEventListener(
    NetStatusEvent.NET_STATUS, // event type
    eNetStatus, //监听函数
    False, //使用捕获?
    0,              // priority
    True //使用弱引用?
);

下面是一个极简的事件监听器的例子,它将摄像头和麦克风连接到流媒体服务器:

private function eNetStatus(e:NetStatusEvent):void
{
    switch (e.info.code) {
        case "NetConnection.Connect.Success":
        camera = Camera.getCamera();
        mic = Microphone.getMicrophone();
        ns = new NetStream(nc);               
        ns.publish(streamName, "live");
        ns.attachCamera(camera);
        ns.attachAudio(mic); 
        break;

    case "NetConnection.Connect.Closed":
        // debug trace... display user message
        break;
}

客户端代码非常相似,除了我们只是在用户端显示视频输入. 这是通过将流连接到 Video 对象,如下面的简单示例所示:

if(event.info.code == "NetConnection.Connect.Success")
{
    ns = new NetStream(nc);
    ns.client = nsClient;
    ns.addEventListener (NetStatusEvent.NET_STATUS, nsClient.onNetStatus);

    ns.play(streamName);
    video = new Video();
    addChild(video); // this will display video 
    video.attachNetStream(ns); // connect NetStream to video
}

Wrap up

直播和视频将在移动和网络应用中扮演越来越重要的角色. 因此,对……很重要 web developers 熟悉视频转码、处理和流媒体. Numerous tools, libraries, 目前存在将这些功能整合到web应用程序中的服务. 本文展示了我们如何利用和集成这些技术,从而相对轻松地成功创建一个基本的类似youtube的站点.

聘请Toptal这方面的专家.
Hire Now
Krzysztof Ożóg的个人资料图片
Krzysztof Ożóg

Located in Kraków, Poland

Member since November 4, 2014

About the author

Krzysztof是一名熟练的Symfony开发人员,对Symfony 2有很好的了解, Symfony 3, PHP, and OOP coding.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Years of Experience

16

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.