Wowza 및 Amazon Elastic Transcoder를 사용한 온라인 비디오

게시 됨: 2022-03-11

오늘날 모든 웹 앱의 성공과 채택은 성능, 유연성 및 사용 용이성에 크게 좌우됩니다.

특히 오늘날의 ADHD 세계에서 사용자는 페이지 로드 시간이 너무 오래 걸리면 앱에 대한 인내심을 빨리 잃게 됩니다. 본질적으로 컴퓨팅 및 I/O 집약적인 비디오 처리를 지원해야 하는 웹 앱의 경우 이 문제는 특히 심각합니다. 그럼에도 불구하고 사용자는 스마트폰이나 태블릿에서 실행하는 경우에도 비디오를 고품질 빠르게 로드하기를 원하며 점점 더 많은 요구를 하고 있습니다.

또한 사용자는 선호하는 브라우저나 장치에서 작동하지 않거나 로드하거나 내보내는 데 필요한 데이터 형식을 지원하지 않는 웹 앱에 대한 내성을 상실하고 있습니다. 따라서 지원해야 하는 비디오 형식의 다양성은 비디오 지원을 웹 앱에 통합하는 것을 특히 어렵게 만듭니다.

이 게시물은 어떻게 내가 오픈 소스 기술과 클라우드 기반 서비스를 효과적으로 활용하여 PHP 기반 웹 앱에 비디오 기능을 통합했는지 설명합니다.

Wowza 및 Amazon Elastic Transcoder를 사용한 PHP의 온라인 비디오 처리

사용 사례

저는 등록된 사용자가 자신의 비디오를 업로드하고 공유할 수 있는 YouTube와 같은 웹사이트를 개발해야 하는 팀의 일원이었습니다.

시스템은 등록된 사용자가 지원되는 다양한 형식으로 비디오를 업로드할 수 있도록 허용한 다음 이를 공통 형식(MP4)으로 변환해야 했습니다. 또한 비디오 진행률 표시줄에 프레임을 표시하기 위해 비디오 플레이어에서 사용할 썸네일 세트와 이미지 콜라주를 생성해야 했습니다.

클라이언트 요구 사항으로 인해 사용 가능한 CDN 또는 트랜스코딩 API를 사용할 수 없었기 때문에 상황이 더욱 복잡해져서 솔루션을 처음부터 개발해야 했습니다.

동영상 업로드

업로드 프로세스 자체가 비디오 전용일 필요가 없었기 때문에(사용하기 쉬운 파일 업로드 기능만 필요했습니다), 자체적으로 롤링하는 것보다 기존 오픈 소스 솔루션을 사용하는 것이 합리적이었습니다. jQuery-File-Upload를 선택한 이유는 주로 우리의 경우에 필수적인 두 가지 기능을 지원했기 때문입니다. 즉, 업로드 진행률 표시줄 및 청크 업로드.

청크 업로드를 통해 사용자는 거의 모든 크기의 비디오 파일을 업로드할 수 있습니다(특히 HD 해상도의 비디오 파일을 지원하는 데 중요). 이 접근 방식을 사용하면 파일이 프런트 엔드에서 여러 "청크"로 분할되어 각 데이터 청크(청크 번호 및 총 파일 크기와 같은 각 청크에 대한 메타데이터와 함께)로 업로드 작업을 호출합니다. 그런 다음 전체 비디오 파일이 백엔드에서 재조립됩니다. 덧붙여서, 메타데이터에 청크 번호를 포함하는 것은 일부 브라우저(모바일 사파리와 같은)가 무작위 순서로 청크를 전송하는 경향이 있기 때문에 특히 중요한 것으로 판명되었습니다.

온라인 비디오 처리

비디오 처리는 스틸 이미지로 프레임을 캡처하는 것처럼 간단할 수도 있고 이미지 향상, 비디오 스트림 안정화 등과 같은 보다 복잡한 작업을 포함할 수도 있습니다. 우리의 경우 유일한 비디오 처리 요구 사항은 (a) 비디오 코덱 및 기타 주요 메타데이터를 추출하고 (b) 썸네일 세트와 이미지 콜라주를 생성하는 것이었습니다(비디오 진행률에 프레임을 표시하기 위해 비디오 플레이어에서 사용 술집).

널리 사용되는 무료 배포 오픈 소스 라이브러리인 FFmpeg 는 이러한 요구 사항을 충족하는 데 매우 유용했습니다. FFmpeg는 오디오 및 비디오 파일을 녹음, 변환 및 스트리밍하기 위한 완벽한 크로스 플랫폼 솔루션을 제공합니다. 또한 비디오를 변환하고 간단한 편집(예: 트리밍, 자르기, 워터마크 추가 등)을 수행하는 데 사용할 수도 있습니다.

우리의 목적을 위해 FFmpeg를 사용하여 비디오를 10개의 섹션으로 분할한 다음 필요한 기능을 제공하기 위해 각 섹션의 썸네일을 캡처할 수 있었습니다.

불행히도 FFmpeg 라이브러리에 대한 PHP 언어 바인딩은 없습니다. 결과적으로 PHP에서 FFmpeg를 활용하는 유일한 방법은 시스템 명령을 사용하여 명령줄에서 바이너리를 호출하는 것입니다. 기본적으로 PHP에서 FFmpeg를 사용하는 두 가지 방법이 있습니다.

  • 리바브. Libav는 2011년 FFmpeg에서 분기된 자유 소프트웨어 프로젝트로 멀티미디어 데이터를 처리하기 위한 라이브러리와 프로그램을 생성합니다. 예를 들어 Ubuntu에서는 sudo apt-get install libav-tools 명령으로 설치할 수 있습니다. libav 명령은 FFmpeg 및 avconv와 호환됩니다. PHP는 이를 프로그래밍 방식으로 사용하기 위해 ffmpeg/avconv 에 대한 명령줄 액세스 권한이 있어야 합니다.
  • PHP-FFMPEG. PHP-FFMpeg는 FFMpeg 바이너리용 객체 지향 PHP 드라이버입니다. composer update "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에서 처리할 수 없으며 일부 형식은 적절하게(또는 완전히) 지원되지 않습니다. 예를 들어 2년 전 피처폰 지원이 필수였을 때 .3gp 형식으로 어려움을 겪었던 기억이 납니다.

큐잉

비디오의 코덱 및 기타 메타데이터를 가져온 후 비디오를 FIFO(선입선출) 변환 대기열로 푸시합니다. 대기열은 실행할 때마다 처리되지 않은 비디오의 주어진 수를 선택하고 변환 유틸리티에 전달하는 간단한 cron 스크립트를 사용하여 구현되었습니다(샘플 소스 코드는 여기에서 사용 가능).

변환 유틸리티는 FFMpeg를 호출하여 변환을 수행하고 각 비디오를 처리된 것으로 표시합니다.

우리는 또한 1분의 비디오를 변환하는 평균 시간을 계산하는 간단한 대기 시간 추정 메커니즘을 개발했습니다. 이 평균을 사용하여 비디오가 처리될 남은 시간(분)을 기반으로 비디오 업로드가 완료된 후 남은 예상 처리 시간을 계산하고 사용자에게 표시할 수 있습니다.

비디오 형식 변환

모든 장치 및 이미지 처리 소프트웨어에서 기본적으로 지원하는 정지 이미지에 대해 보편적으로 인식되는 특정 형식(예: JPEG 및 GIF)이 등장했습니다. 일부 비디오 형식은 다른 형식보다 더 일반적이지만 비디오에 대해 보편적으로 지원되는 형식은 아직 나타나지 않았습니다.

우리의 경우 다양한 형식에서 단일 공통 형식(MPEG-4)으로 변환해야 하는 것 외에도 변환된 비디오가 모바일 장치로 스트리밍하도록 최적화되어야 했습니다.

비디오 형식 변환의 경우(적어도 단기적인 요구 사항에서는) 클라우드 기반 Amazon Elastic Transcoder 를 사용하는 것이 가장 좋은 옵션이었습니다. 일반적인 사용 편의성 외에도 트랜스코더 서비스는 최적화 및 모든 인코딩 설정을 처리합니다. 다행히 PHP용 AWS SDK를 사용할 수 있어 PHP 코드에서 서비스를 간단하게 호출할 수 있습니다.

참고: Amazon Elastic Transcoder와 같은 클라우드 기반 서비스를 사용하는 것은 빠르게 시작하고 실행하려는 경우에 좋습니다. 그러나 특히 비즈니스 모델이 대용량 비디오를 광범위하게 사용해야 하는 경우 이 옵션은 고객에게 비용이 많이 들 수 있다는 점을 염두에 두십시오. 고려해야 할 또 다른 요소는 고객의 비디오 또는 비즈니스 모델이 서비스 약관과 호환될 것이라고 반드시 가정해서는 안 된다는 것입니다.

Amazon은 Auto Scaling 및 SNS(Simple Notification Service)와 결합된 기본 스토리지 및 컴퓨팅 요소인 S3(Simple Storage Service) 및 EC2(Elastic Compute Cloud)를 사용하여 사실상 즉시 확장 및 축소할 수 있는 기능을 제공합니다.

Amazon에서 패키지의 Composer 설치 가능 버전을 유지 관리하기 때문에 aws-sdk 설치는 간단합니다. ”aws/aws-sdk-php": "2.*"composer.json 파일에 추가하고 composer update 를 수행하십시오.

분명히 Amazon Elastic Transcoder에 액세스하려면 Amazon 계정이 필요하므로 귀하(또는 귀하의 고객)가 아직 계정이 없는 경우에도 계정을 설정해야 합니다.

Amazon Elastic Transcoder 서비스를 사용하려면 먼저 S3의 적절한 버킷에 비디오 파일을 업로드해야 했습니다. 그런 다음 완료 시 지정된 주소에 HTTP 요청을 게시하는 썸네일 디코딩 및 생성을 담당하는 트랜스코더 작업을 만들었습니다. 이를 위해서는 AWS 패널에서 일부 구성이 필요하지만 매우 간단하며 Amazon에서 이를 수행하는 방법에 대한 좋은 문서를 제공합니다.

Symfony 2에 대한 통합을 단순화하는 데 도움이 되는 트랜스코더 번들을 자유롭게 사용하십시오. 여기에는 사용 설명이 포함되어 있으며 처리된 비디오에 대한 정보를 수집하기 위해 Amazon에서 보낸 알림 서비스를 빠르게 구현하기 위한 컨트롤러를 제공합니다. 여기에서 사용 예를 볼 수 있습니다.

또한 Amazon 알림을 처리하는 예제 컨트롤러는 여기에서 구독 주소 확인도 구현합니다. 서비스는 먼저 이것이 유효한 알림 수신자인지 확인하기 위해 방문할 URL을 게시합니다. 그런 다음 실제로 필요한 것은 비디오를 처리된 것으로 표시하는 것입니다. 그때부터 클라우드에 저장된 트랜스코딩된 비디오를 사용할 수 있습니다.

스트리밍

비디오 스트리밍은 고성능이 필요한 기능입니다. 중단 없는 스트리밍에 대한 사용자 기대치는 높고 대기 시간에 대한 허용 오차는 매우 낮습니다. 이 문제는 실시간으로 동시에 여러 클라이언트에 비디오를 스트리밍해야 하는 필요성으로 인해 악화되는 경우가 많습니다.

우리의 경우 각 사용자가 자신의 비디오 채널을 만들고 방송을 시작할 수 있도록 지원해야 했습니다. 우리의 솔루션은 세 가지 구성 요소로 구성되어 있습니다.

  • 계기반. 비디오를 제공하는 기능을 제공하는 스트리머의 대시보드 역할을 하는 응용 프로그램입니다.
  • 뷰어. 비디오 스트림을 소비하고 표시하는 비디오 클라이언트.
  • 스트리밍 엔진. 클라우드 기반 동영상 스트리밍 서비스.

VOD(주문형 비디오) 기술이 계속 발전하고 있다는 사실 외에도 우리가 직면한 또 다른 문제는 카메라 액세스가 제대로 지원되지 않고 P2P 연결만 제공한다는 것이었습니다. 또한 여러 동시 사용자에게 온라인 방송을 제공하는 것이 목표였습니다. 또한 getUserMedia/Stream API(이전에는 <device> 요소로 구상됨)에 대한 지원은 최신 브라우저에서 아직 일관되지 않습니다. 이러한 요소를 기반으로 플래시 기술이 유일하게 합리적인 선택이었기 때문에 사용하기로 결정했습니다. 따라서 두 응용 프로그램(대시보드 및 뷰어) 모두 Flex 및 ActionScript 를 사용하여 구현되었습니다.

스트리밍 엔진의 경우 Wowza 를 사용했습니다. 다른 비상업적 솔루션(예: 기본적으로 Wowza의 드롭인 대체품으로 판매되는 Red5)이 있지만 우리의 경우 상용 제품 지원이 중요한 요소였습니다. 또한 최소한 시스템을 구축할 당시 Wowza는 추가적인 이점인 더 나은 문서를 제공했습니다. (참고로 Wowza 평가판은 30일 동안 무료로 받을 수 있으며 개발자용 평가판은 최대 180일까지 사용할 수 있습니다. 하지만 몇 가지 제한 사항이 있습니다. 스트리밍은 2개의 클라이언트에서만 작동할 수 있고 제한이 있습니다. 최대 연결 수)

Wowza 스트리밍 엔진

Wowza와 함께 제공되는 LiveStream 애플리케이션을 사용했습니다. 구성하려면 applications/app_name 을 비워두고 conf/app_nameconf 카탈로그에서 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 응용 프로그램일 수 있습니다. 서버는 웹 서버, Flash Media Server, Flash Remoting을 실행하는 응용 프로그램 서버 또는 Adobe Stratus 서비스일 수 있습니다.
  • 카메라. Camera 클래스는 클라이언트 시스템 또는 장치 카메라에서 비디오를 캡처하는 데 사용됩니다.
  • 마이크로폰. Microphone 클래스는 마이크에서 오디오를 모니터링하거나 캡처하는 데 사용됩니다.
  • 넷스트림. 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 }

마무리

라이브 스트리밍과 비디오는 모바일 및 웹 애플리케이션에서 점점 더 중요한 역할을 할 것으로 예상할 수 있습니다. 따라서 웹 개발자가 비디오 트랜스코딩, 처리 및 스트리밍에 익숙해지는 것이 중요합니다. 오늘날 이러한 기능을 웹 애플리케이션에 통합하기 위한 수많은 도구, 라이브러리 및 서비스가 존재합니다. 이 기사에서는 이러한 기술을 활용하고 통합하여 비교적 쉽게 기본적인 YouTube와 같은 사이트를 성공적으로 만든 방법을 보여줍니다.