本文概述
当今任何Web应用程序的成功与成功都很大程度上取决于其性能, 灵活性和易用性。
特别是在当今的ADHD世界中, 如果页面加载时间过长, 用户将很快对应用失去耐心。对于需要支持视频处理的Web应用程序(本质上是计算和I / O密集型), 这一挑战尤为严峻。尽管如此, 用户的要求也越来越高, 他们希望即使在智能手机或平板电脑上运行视频也要高质量并快速加载。
对于无法在其首选浏览器或设备上运行或不支持其加载或导出数据格式的网络应用, 用户也将失去容忍度。因此, 需要支持的视频格式的多样性也使得将视频支持整合到Web应用程序中尤其具有挑战性。
这篇文章描述了我如何有效地利用开源技术和基于云的服务, 将视频功能整合到基于PHP的Web应用程序中。
用例
我是一个团队的成员, 该团队需要开发类似YouTube的网站, 注册用户可以在该网站上载和共享他们的视频。
该系统需要允许注册用户以各种受支持的格式上传他们的视频, 然后将其转换为通用格式(MP4)。我们还需要生成一组缩略图和一个图像拼贴, 以便在视频播放器中用于在视频进度条上显示帧。
由于客户要求阻止我们使用任何可用的CDN或代码转换API, 事情变得更加复杂, 因此我们需要从头开始开发解决方案。
影片上传
由于上传过程本身不需要特定于视频(我们只需要易于使用的文件上传功能), 因此使用现有的开源解决方案而不是自己动手开发是有意义的。我们选择jQuery-File-Upload, 主要是因为它支持我们的案例中必不可少的两个功能。即上传进度条和分块上传。
批量上传使我们能够允许用户上传几乎任何大小的视频文件(对于支持HD分辨率的视频文件尤其重要)。通过这种方法, 文件在前端被分为多个”块”, 从而对每个数据块(以及每个块的元数据, 例如块号和总文件大小)调用上载操作。完整的视频文件然后在后端重新组合。顺便说一句, 在元数据中包括块编号被证明特别重要, 因为某些浏览器(例如Mobile Safari)倾向于随机地传输块。
在线视频处理
视频处理可以像捕获静止图像一样简单, 也可以涉及更复杂的操作, 例如图像增强, 稳定视频流等。在我们的案例中, 唯一的视频处理要求是(a)提取视频编解码器和其他关键元数据, 以及(b)生成一组缩略图和图像拼贴(用于视频播放器中以显示视频进度中的帧)酒吧)。
FFmpeg(一种广泛使用, 免费分发的开源库)在满足这些要求方面非常有帮助。 FFmpeg提供了一个完整的跨平台解决方案, 用于记录, 转换和流式传输音频和视频文件。它也可以用于转换视频并进行简单的编辑(例如, 修剪, 剪切, 添加水印等)。
出于我们的目的, 我们能够使用FFmpeg将视频分为十个部分, 然后为每个部分捕获一个缩略图以提供所需的功能。
但是, 不幸的是, FFmpeg库没有PHP语言绑定。因此, 从PHP利用FFmpeg的唯一方法是使用系统命令从命令行调用二进制文件。在PHP中使用FFmpeg基本上有两种方法:
- libav。 Libav是一个免费软件项目, 由FFmpeg于2011年派生, 该项目产生用于处理多媒体数据的库和程序。例如, 在Ubuntu上, 可以使用命令sudo apt-get install libav-tools进行安装。 libav命令与FFmpeg和avconv兼容。 PHP必须具有对ffmpeg / avconv的命令行访问权, 才能以编程方式使用此功能。
- PHP-FFMpeg。 PHP-FFMpeg是用于FFMpeg二进制文件的面向对象的PHP驱动程序。只需执行作曲家更新” php-ffmpeg / php-ffmpeg”即可访问它。
我们使用PHP-FFMpeg是因为它可以轻松访问我们感兴趣的FFmpeg功能。例如, 此软件包中的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');
此处提供了更详细的示例代码。
注意事项之一:由于某些专利法, FFmpeg不能处理所有编解码器, 并且某些格式不正确(或不完全)受支持。记得几年前, 例如.3gp格式在必须支持功能电话的情况下挣扎。
排队
获取视频的编解码器和其他元数据后, 我们将视频推入FIFO(先进先出)转换队列。使用简单的cron脚本实现了队列, 该脚本每次运行时都会选择给定数量的未处理视频, 并将其传递给转换实用程序(此处提供示例源代码)。
转换实用程序调用FFMpeg进行转换, 并将每个视频标记为已处理。
我们还开发了一种简单的等待时间估算机制, 该机制可以计算转换1分钟视频的平均时间。使用该平均值, 我们可以根据剩余的视频处理时间, 为用户计算并显示视频完成上传后的估计剩余处理时间。
视频格式转换
静态图像已经出现了某些普遍认可的格式(例如JPEG和GIF), 而所有设备和图像处理软件基本上都支持这种格式。尽管某些视频格式比其他视频格式更常见, 但尚未出现这种普遍支持的视频格式。
在我们的案例中, 除了需要从多种格式转换为单一的通用格式(MPEG-4)外, 我们还需要对转换后的视频进行优化, 以流至移动设备。
对于视频格式转换(至少满足我们的短期需求), 使用基于云的Amazon Elastic Transcoder是最佳选择。除了一般的易用性之外, 代码转换器服务还负责优化和所有编码设置。幸运的是, 有一个适用于PHP的AWS开发工具包, 它简化了从我们的PHP代码中调用服务的过程。
注意:如果你想快速启动并运行, 那么使用像Amazon Elastic Transcoder这样的基于云的服务非常有用。但是, 请记住, 此选项对你的客户而言可能会变得昂贵, 尤其是在其商业模式可能需要广泛使用大型视频的情况下。要考虑的另一个因素是, 你不必一定假定客户的视频或商业模式将与服务条款兼容。
亚马逊使用其基本存储和计算元素S3(简单存储服务)和EC2(弹性计算云)以及Auto Scaling和SNS(简单通知服务)相结合, 可提供即时扩展和缩减的功能。
由于Amazon维护该软件包的Composer可安装版本, 因此aws-sdk的安装非常简单。只需在你的composer.json文件中添加” aws / aws-sdk-php”:” 2. *”, 然后进行composer更新即可。
显然, 访问Amazon Elastic Transcoder需要一个Amazon帐户, 因此, 如果你(或你的客户)还没有一个帐户, 则还需要进行设置。
我们对Amazon Elastic Transcoder服务的使用需要首先将视频文件上传到S3上的相应存储桶。然后, 我们使代码转换器作业负责解码并生成缩略图, 该缩略图完成后会将HTTP请求发布到指定地址。这确实需要在AWS面板中进行一些配置, 但这非常简单, Amazon提供了有关如何执行此操作的良好文档。
随意使用我们的代码转换器捆绑包, 这有助于简化Symfony 2的集成。它包括用法说明, 并提供了一个控制器, 用于快速实施Amazon发送的通知服务以收集有关已处理视频的信息。这里有一个用法示例。
此外, 此处提供了处理亚马逊通知的示例控制器, 该控制器还实现了订阅地址的确认。该服务将首先发布要访问的URL, 以确认这是有效的通知接收者。真正需要的就是将视频标记为已处理。从那时起, 我们可以使用存储在云中的转码视频。
流媒体
视频流是必须具备高性能的功能:用户对不间断流的期望很高, 而对延迟的容忍度则非常低。实时将视频同时流传输到多个客户端的需求常常加剧了这一挑战。
在我们的案例中, 我们需要支持每个用户都能创建自己的视频频道并开始广播。我们的解决方案包括三个部分:
- 仪表板。可以用作流媒体信息中心的应用程序, 可以提供视频服务。
- 查看者。使用并显示视频流的视频客户端。
- 流引擎。基于云的视频流服务。
除了视频点播(VOD)技术仍在发展的事实外, 我们面临的另一个问题是摄像头访问没有得到很好的支持, 仅提供P2P连接。此外, 我们的目标是为多个并发用户提供在线广播。此外, 在现代浏览器中, 对getUserMedia / Stream API(以前设想为<device>元素)的支持还不一致。基于这些因素, 我决定使用Flash技术, 因为它确实是唯一合理的选择。因此, 两个应用程序(仪表板和查看器)都使用Flex和ActionScript来实现。
对于流引擎, 我们使用了Wowza。尽管还有其他非商业解决方案(例如Red5, 其本质上是替代Wowza的替代品), 但在我们的案例中, 商业产品支持是一个重要因素。另外, 至少在我们构建系统时, Wowza提供了更好的文档, 这是另一个优势。 (请注意, 你可以免费获得30天的Wowza试用版, 还有开发人员的试用版, 最多可以使用180天。但是有一些限制;流技术只能用于两个客户端, 并且存在限制在最大连接数上。)
Wowza流媒体引擎
我们使用了Wowza随附的LiveStream应用程序。要对其进行配置, 请将application / app_name保留为空, 并在conf / app_name中从conf目录中复制Application.xml文件。编辑文件以配置<Streams>部分, 如下所示:
<Streams>
<StreamType>live</StreamType>
<StorageDir>${com.wowza.wms.context.VHostConfigHome}/content</StorageDir>
<KeyDir>${com.wowza.wms.context.VHostConfigHome}/keys</KeyDir>
<LiveStreamPacketizers></LiveStreamPacketizers>
<Properties></Properties>
</Streams>
关键参数是<StreamType> live </ StreamType>, 它定义这将是来自实时视频源(例如摄像机)的流。请注意, 在编辑和保存此文件后, 你将需要重新启动Wowza。
Flash(Flex / ActionScript)应用程序
Flash提供了一个完全集成的系统, 可将相机和麦克风连接到Wowza流服务器。如果你对ActionScript的使用经验有限, 这将特别有用。
整个应用程序基本上基于以下对象之间的交互:
- 网络连接。 NetConnection类在客户端和服务器之间创建双向连接。客户端可以是Flash Player或AIR应用程序。该服务器可以是Web服务器, Flash Media Server, 运行Flash Remoting的应用程序服务器或Adobe Stratus服务。
- 相机。 Camera类用于从客户端系统或设备相机捕获视频。
- 麦克风。 Microphone类用于监视或捕获来自麦克风的音频。
- NetStream。 NetStream类通过NetConnection打开一个单向流通道。
首先, 我们使用NetConnection实例连接到Wowza流服务器, 然后附加事件侦听器, 该侦听器将侦听网络连接状态的变化:
nc = new NetConnection();
nc.connect(serverAddress:string);
nc.addEventListener(
NetStatusEvent.NET_STATUS, // event type
eNetStatus, // listener function
false, // use capture?
0, // priority
true // use weak reference?
);
这是一个将摄像机和麦克风连接到流服务器的事件监听器的简单示例:
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
}
本文总结
可以预期, 实时流和视频将在移动和Web应用程序中扮演越来越重要的角色。因此, 对于Web开发人员来说, 熟悉视频转码, 处理和流传输非常重要。如今, 有许多工具, 库和服务可用于将这些功能整合到Web应用程序中。本文说明了我们如何利用和整合许多这些技术来相对轻松地成功创建一个类似YouTube的基本网站。
评论前必须登录!
注册