node.js를 사용하여 ffmpeg의 실시간 출력을 HTML5 클라이언트로 스트리밍하는 가장 좋은 방법을 이해하려고 노력하고 있습니다. 여기에 많은 변수가 있으며이 공간에 대한 경험이 많지 않기 때문에, 다른 조합을 시도하는 데 많은 시간을 보냈습니다.
내 유스 케이스는 다음과 같습니다.
1) IP 비디오 카메라 RTSP H.264 스트림은 FFMPEG에 의해 픽업되고 노드의 다음 FFMPEG 설정을 사용하여 mp4 컨테이너로 리 뮤직되어 STDOUT으로 출력됩니다. 이것은 초기 클라이언트 연결에서만 실행되므로 부분 컨텐츠 요청은 FFMPEG를 다시 생성하려고 시도하지 않습니다.
liveFFMPEG = child_process.spawn("ffmpeg", [
"-i", "rtsp://admin:12345@192.168.1.234:554" , "-vcodec", "copy", "-f",
"mp4", "-reset_timestamps", "1", "-movflags", "frag_keyframe+empty_moov",
"-" // output to stdout
], {detached: false});
2) 노드 http 서버를 사용하여 STDOUT을 캡처하고 클라이언트 요청시 클라이언트로 다시 스트리밍합니다. 클라이언트가 처음 연결되면 위의 FFMPEG 명령 줄을 생성 한 다음 STDOUT 스트림을 HTTP 응답으로 파이프합니다.
liveFFMPEG.stdout.pipe(resp);
또한 스트림 이벤트를 사용하여 FFMPEG 데이터를 HTTP 응답에 쓰지만 차이는 없습니다.
xliveFFMPEG.stdout.on("data",function(data) {
resp.write(data);
}
다음 HTTP 헤더를 사용합니다 (사전 녹음 된 파일을 스트리밍 할 때도 사용됨)
var total = 999999999 // fake a large file
var partialstart = 0
var partialend = total - 1
if (range !== undefined) {
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
}
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total; // fake a large file if no range reques
var chunksize = (end-start)+1;
resp.writeHead(206, {
'Transfer-Encoding': 'chunked'
, 'Content-Type': 'video/mp4'
, 'Content-Length': chunksize // large size to fake a file
, 'Accept-Ranges': 'bytes ' + start + "-" + end + "/" + total
});
3) 클라이언트는 HTML5 비디오 태그를 사용해야합니다.
위의 FFMPEG 명령 줄로 이전에 기록 된 비디오 파일 (STDOUT 대신 파일에 저장 됨)을 HTML5 클라이언트에 스트리밍 재생 (206 HTTP 부분 컨텐츠로 fs.createReadStream 사용)에 문제가 없으므로 FFMPEG 스트림을 알고 있습니다. HTTP 노드 서버에 연결할 때 VLC에서 비디오 라이브 스트리밍을 올바르게 볼 수도 있습니다.
그러나 노드 HTTP를 통해 FFMPEG에서 실시간 스트리밍을 시도하는 것은 클라이언트가 한 프레임을 표시 한 다음 중지하기 때문에 훨씬 어려워 보입니다. 문제는 HTML5 비디오 클라이언트와 호환되도록 HTTP 연결을 설정하지 않았다는 것입니다. HTTP 206 (부분 내용)과 200 응답을 사용하여 데이터를 버퍼에 넣은 다음 운없이 스트리밍하는 것과 같은 다양한 작업을 시도 했으므로 첫 번째 원칙으로 돌아가서 올바르게 설정해야합니다. 방법.
이것이 어떻게 작동하는지에 대한 나의 이해는 다음과 같습니다. 틀린 경우 수정하십시오.
1) 출력을 조각화하고 빈 moov (FFMPEG frag_keyframe 및 empty_moov mov 플래그)를 사용하도록 FFMPEG를 설정해야합니다. 이것은 클라이언트가 일반적으로 파일의 끝 부분에있는 moov atom을 사용하지 않으며 스트리밍 할 때 관련이 없지만 (파일 끝 없음) 내 유스 케이스에 적합한 탐색을 의미하지 않습니다.
2) MP4 조각과 빈 MOOV를 사용하더라도 HTML5 플레이어는 전체 스트림이 다운로드 될 때까지 기다릴 것이므로 라이브 스트림으로 끝나지 않으므로 작동 할 수 없으므로 HTTP 부분 내용을 사용해야합니다.
3) 라이브 스트리밍 할 때 STDOUT 스트림을 HTTP 응답으로 파이핑하는 것이 왜 작동하지 않는지 아직 알 수 없습니다. 파일로 저장하면 비슷한 코드를 사용 하여이 파일을 HTML5 클라이언트로 쉽게 스트리밍 할 수 있습니다. FFMPEG 스폰이 시작되고 IP 카메라에 연결되어 청크를 노드에 보내는데 노드 데이터 이벤트도 불규칙하므로 시간 문제 일 수 있습니다. 그러나 바이트 스트림은 파일에 저장하는 것과 정확히 동일해야하며 HTTP는 지연을 수용 할 수 있어야합니다.
4) 카메라에서 FFMPEG로 생성 된 MP4 파일을 스트리밍 할 때 HTTP 클라이언트에서 네트워크 로그를 확인할 때 3 가지 클라이언트 요청이 있습니다. 비디오에 대한 일반적인 GET 요청, HTTP 서버는 약 40Kb를 반환 한 다음 부분적으로 파일의 마지막 10K에 대한 바이트 범위를 가진 콘텐츠 요청, 중간에 비트에 대한 최종 요청이로드되지 않았습니다. 어쩌면 HTML5 클라이언트가 첫 번째 응답을 받으면 파일의 마지막 부분에서 MP4 MOOV 원자를로드하도록 요구하고 있습니까? 이 경우 MOOV 파일이없고 파일 끝이 없으므로 스트리밍에 사용할 수 없습니다.
5) 실시간 스트리밍을 시도 할 때 네트워크 로그를 확인할 때 약 200 바이트 만 수신 된 초기 요청이 중단 된 다음 200 바이트로 다시 요청이 중단되고 세 번째 요청은 2K입니다. 바이트 스트림이 기록 된 파일에서 스트리밍 할 때 성공적으로 사용할 수있는 것과 정확히 동일하므로 HTML5 클라이언트가 요청을 중단하는 이유를 이해하지 못합니다. 또한 노드가 나머지 FFMPEG 스트림을 클라이언트로 보내지 않는 것 같지만 .on 이벤트 루틴에서 FFMPEG 데이터를 볼 수 있으므로 FFMPEG 노드 HTTP 서버에 도착합니다.
6) STDOUT 스트림을 HTTP 응답 버퍼로 파이프하는 것이 작동해야한다고 생각하지만 HTTP 부분 컨텐츠 클라이언트 요청이 파일을 읽을 때와 같이 올바르게 작동하도록 중간 버퍼 및 스트림을 빌드해야합니다 ? 나는 이것이 내 문제의 주된 이유라고 생각하지만 노드에서 그 설정을 가장 잘하는 방법을 정확히 모르겠습니다. 그리고 파일 끝이 없기 때문에 파일 끝에서 데이터에 대한 클라이언트 요청을 처리하는 방법을 모르겠습니다.
7) 206 개의 부분 컨텐츠 요청을 처리하려고하는데 잘못된 트랙에 있고 정상적인 200 HTTP 응답으로 작동해야합니까? HTTP 200 응답은 VLC에서 잘 작동하므로 HTML5 비디오 클라이언트가 부분 콘텐츠 요청에서만 작동한다고 생각합니까?
여전히이 내용을 배우 면서이 문제의 다양한 계층 (FFMPEG, 노드, 스트리밍, HTTP, HTML5 비디오)을 통해 작업하기가 어려우므로 모든 포인터를 높이 평가할 것입니다. 나는이 사이트와 인터넷에서 조사하는 데 몇 시간을 보냈으며 노드에서 실시간 스트리밍을 할 수있는 사람을 만나지 못했지만 처음은 될 수 없으며 이것이 어떻게 작동해야한다고 생각합니다 !).
답변
편집 3 : IOS 10부터 HLS는 조각난 mp4 파일을 지원합니다. 이제 해답은 DASH 및 HLS 매니페스트를 사용하여 조각화 된 mp4 자산을 만드는 것입니다. > 플래시 플래시, iOS9 이하 및 IE 10 이하는 존재하지 않습니다.
이 줄 아래의 모든 것이 오래되었습니다. 후손을 위해 여기에 보관하십시오.
편집 2 : 의견의 사람들이 지적한 것처럼 상황이 바뀝니다. 거의 모든 브라우저가 AVC / AAC 코덱을 지원합니다. iOS에는 여전히 HLS가 필요합니다. 그러나 hls.js와 같은 어댑터를 통해 MSE에서 HLS를 재생할 수 있습니다. iOS가 필요한 경우 새로운 답변은 HLS + hls.js입니다. 또는 조각화되지 않은 MP4 (예 : DASH)
비디오, 특히 라이브 비디오가 매우 어려운 이유는 여러 가지가 있습니다. (원래의 질문은 HTML5 비디오가 요구 사항이라고 명시했지만 어커는 의견에 플래시가 가능하다고 언급했습니다. 따라서 즉시이 질문은 오도됩니다)
먼저 HTML5 이상의 라이브 스트리밍에 대한 공식 지원은 없습니다 . 해킹이 있지만 마일리지가 다를 수 있습니다.
편집 : 나는이 답변을 쓴 이후 미디어 소스 확장은 성숙하고 이제는 가능한 옵션이되는 것에 매우 가깝습니다. 대부분의 주요 브라우저에서 지원됩니다. iOS는 계속 유지되고 있습니다.
다음으로 주문형 비디오 (VOD)와 라이브 비디오가 매우 다르다는 것을 이해해야합니다. 예, 둘 다 비디오이지만 문제는 다르므로 형식이 다릅니다. 예를 들어, 컴퓨터의 시계가 예상보다 1 % 빠르게 실행되면 VOD에 표시되지 않습니다. 라이브 비디오를 사용하면 비디오가 발생하기 전에 비디오를 재생하려고합니다. 진행중인 라이브 비디오 스트림에 참여하려면 디코더를 초기화하는 데 필요한 데이터가 필요하므로 스트림에서 반복하거나 대역 외로 보내야합니다. VOD를 사용하면 원하는 지점에서 원하는 파일의 시작 부분을 읽을 수 있습니다.
이제 조금 파헤쳐 보자.
플랫폼 :
- iOS
- PC
- 맥
- 기계적 인조 인간
코덱 :
- vp8 / 9
- h.264
- 토라 (vp3)
브라우저에서 라이브 비디오를위한 일반적인 전달 방법 :
- 대시 (HTTP)
- HLS (HTTP)
- 플래시 (RTMP)
- 플래시 (HDS)
브라우저에서 VOD를위한 일반적인 전달 방법 :
- 대시 (HTTP 스트리밍)
- HLS (HTTP 스트리밍)
- 플래시 (RTMP)
- 플래시 (HTTP 스트리밍)
- MP4 (HTTP 의사 스트리밍)
- MKV와 OOG에 대해서는 잘 모르기 때문에 이야기하지 않겠습니다.
html5 비디오 태그 :
- MP4
- 웹
- 오그
어떤 브라우저가 어떤 형식을 지원하는지 확인할 수 있습니다
원정 여행:
- HLS (iOS 및 Mac 만 해당)
- h.264
- MP4
Firefox
- DASH (MSE를 통하지 만 h.264는 아님)
- 플래시를 통해서만 h.264!
- VP9
- MP4
- 오그
- 웹
IE
- 플래시
- 대시 (MSE IE 11+를 통해서만)
- h.264
- MP4
크롬
- 플래시
- 대시 (MSE를 통해)
- h.264
- VP9
- MP4
- 웹
- 오그
MP4는 라이브 비디오에 사용할 수 없습니다 (참고 : DASH는 MP4의 상위 세트이므로 혼동하지 마십시오). MP4는 moov와 mdat의 두 부분으로 나뉩니다. mdat에는 원시 오디오 비디오 데이터가 포함됩니다. 그러나 색인이 생성되지 않았으므로 무브가 없으면 쓸모가 없습니다. moov에는 mdat의 모든 데이터 색인이 포함됩니다. 그러나 형식으로 인해 모든 프레임의 타임 스탬프 및 크기를 알 때까지 ‘평평하게’할 수 없습니다. 프레임 크기를 ‘고정’하는 무브를 구성하는 것이 가능하지만 대역폭 측면에서는 매우 낭비입니다.
따라서 모든 곳에서 배송하려면 최소 공통 분모를 찾아야합니다. 플래시 예제를 사용하지 않고 LCD가 없다는 것을 알 수 있습니다.
- iOS는 h.264 비디오 만 지원합니다. 라이브 용 HLS 만 지원합니다.
- 플래시를 사용하지 않으면 Firefox는 h.264를 전혀 지원하지 않습니다
- iOS에서 플래시가 작동하지 않습니다
LCD에 가장 가까운 것은 HLS를 사용하여 iOS 사용자를 확보하고 다른 사람들을 위해 플래시하는 것입니다. 개인적으로 가장 좋아하는 것은 HLS를 인코딩 한 다음 플래시를 사용하여 다른 사람을 위해 HLS를 재생하는 것입니다. JW 플레이어 6을 통해 플래시에서 HLS를 재생할 수 있습니다 (또는 내가했던 것처럼 AS3에서 FLV에 자신의 HLS를 쓸 수 있음)
곧이 작업을 수행하는 가장 일반적인 방법은 iOS / Mac의 HLS와 MSE를 통한 DASH입니다 (Netflix가 곧 수행 할 예정 임). 그러나 우리는 여전히 모든 사람들이 브라우저를 업그레이드하기를 기다리고 있습니다. Firefox 용 별도의 DASH / VP9도 필요할 것입니다 (open264에 대해 알고 있습니다. 짜증납니다. 메인 또는 하이 프로파일로 비디오를 재생할 수 없으므로 현재 쓸모가 없습니다).
답변
이것은 복잡한 질문이므로 많은 사람들에게 특히 감사합니다. 라이브 레이어를 스트리밍하기 전에 모든 레이어가 작동해야합니다. 내 원래 질문과 HTML5 비디오 사용 대 플래시를 명확히하기 위해 유스 케이스는 클라이언트와 미래에 일반적이고 구현하기 쉽기 때문에 HTML5를 강력하게 선호합니다. 플래시는 먼 두 번째 방법 이므로이 질문에 HTML5를 사용하십시오.
이 연습을 통해 많은 것을 배웠으며 라이브 스트리밍이 VOD (HTML5 비디오와 잘 작동 함)보다 훨씬 어렵다는 데 동의합니다. 그러나 필자는 유스 케이스 에서이 작업을 만족스럽게 수행했으며 노드의 MSE, 플래시, 정교한 버퍼링 체계와 같은보다 복잡한 옵션을 쫓아 솔루션이 매우 간단하게 작동했습니다. 문제는 FFMPEG가 조각난 MP4를 손상시키고 FFMPEG 매개 변수를 조정해야했고, 원래 사용했던 http를 통한 표준 노드 스트림 파이프 리디렉션이 필요한 전부라는 것입니다.
MP4에는 mp4를 자체 인덱스가있는 훨씬 작은 조각으로 나누고 mp4 라이브 스트리밍 옵션을 실행하는 ‘조각화’옵션이 있습니다. 그러나 스트림으로 다시 검색 할 수 없으며 (사용 사례에 대해서는 괜찮음) FFMPEG의 이후 버전은 조각화를 지원합니다.
참고 타이밍 문제가 될 수 있으며 내 솔루션을 사용하면 리 먹싱의 조합으로 인해 2 ~ 6 초의 지연이 발생합니다 (효과적으로 FFMPEG는 라이브 스트림을 수신하고 remux 한 다음 HTTP를 통해 제공하기 위해 노드로 보냅니다) . 이것에 대해 할 수있는 일은 많지 않지만 Chrome에서는 비디오가 가능한 한 많이 따라 잡으려고 시도하므로 IE11 (내가 선호하는 클라이언트)보다 비디오가 약간 튀어 나올 수 있습니다.
이 게시물에서 코드의 작동 방식을 설명하는 대신 주석이 포함 된 GIST를 확인하십시오 (클라이언트 코드는 포함되지 않으며 노드 http 서버 주소가있는 표준 HTML5 비디오 태그입니다). GIST는 다음과 같습니다 : https://gist.github.com/deandob/9240090
이 유스 케이스의 유사한 예를 찾을 수 없었으므로 위의 설명과 코드가 다른 사람들에게 도움이되기를 바랍니다. 특히이 사이트에서 많은 것을 배웠고 여전히 초보자라고 생각합니다!
이것이 내 특정 질문에 대한 답변이지만, 나는 Szatmary의 답변을 가장 포괄적 인 답변으로 채택했습니다.
답변
JSMPEG 프로젝트를 살펴보십시오 . JavaScript를 사용하여 브라우저에서 MPEG를 디코딩하는 것이 좋습니다. 인코더 (예 : FFMPEG)의 바이트는 WebSocket 또는 Flash를 사용하여 브라우저로 전송할 수 있습니다. 커뮤니티가 따라 잡으면 지금은 최고의 HTML5 라이브 비디오 스트리밍 솔루션이 될 것입니다.
답변
나는 모든 브라우저 (데스크톱, iOS 등)에서 라이브 (지연 없음) h264 비디오를 재생할 수있는 브로드 웨이 h264 코덱 (emscripten) 주위에 HTML5 비디오 플레이어를 작성했습니다.
비디오 스트림은 웹 소켓을 통해 클라이언트로 전송되고, 프레임 당 디코딩 된 프레임은 칸 바에 표시됩니다 (가속화를 위해 webgl 사용).
github 에서 https://github.com/131/h264-live-player 를 확인하십시오 .
답변
RTSP 기반 웹캠을 HTML5 클라이언트로 라이브 스트리밍하는 한 가지 방법 (다시 인코딩이 포함되므로 품질 손실이 예상되며 CPU 성능이 필요함) :
- 아이스 캐스트 서버를 설정합니다 (웹 서버가있는 동일한 컴퓨터 또는 캠에서 RTSP 스트림을 수신하는 컴퓨터에있을 수 있음)
-
카메라에서 스트림을 수신하는 기기에서는 FFMPEG를 사용하지 말고 gstreamer를 사용하십시오. RTSP 스트림을 수신 및 디코딩하고 다시 인코딩하여 아이스 캐스트 서버로 스트리밍 할 수 있습니다. 파이프 라인 예 (비디오 만, 오디오 없음) :
gst-launch-1.0 rtspsrc location=rtsp://192.168.1.234:554 user-id=admin user-pw=123456 ! rtph264depay ! avdec_h264 ! vp8enc threads=2 deadline=10000 ! webmmux streamable=true ! shout2send password=pass ip=<IP_OF_ICECAST_SERVER> port=12000 mount=cam.webm
=> 그런 다음 icecast-stream의 URL ( http://127.0.0.1:12000/cam.webm )과 함께 <video> 태그를 사용할 수 있으며 webm을 지원하는 모든 브라우저 및 장치에서 작동합니다
답변
이 솔루션을 살펴보십시오 . 아시다시피 Flashphoner를 사용하면 순수한 HTML5 페이지에서 라이브 오디오 + 비디오 스트림을 재생할 수 있습니다.
그들은 재생을 위해 MPEG1 및 G.711 코덱을 사용합니다. 해킹은 HTML5 캔버스 요소에 디코딩 된 비디오를 렌더링하고 HTML5 오디오 컨텍스트를 통해 디코딩 된 오디오를 재생하는 것입니다.
답변
jpeg 솔루션을 사용하는 방법은 무엇입니까? 서버에서 jpeg를 하나씩 브라우저에 배포 한 다음 canvas 요소를 사용하여 이러한 jpeg를 그립니다.
http://thejackalofjavascript.com/rpi-live-streaming/