Jeg' sitter virkelig fast og prøver å forstå den beste måten å streame sanntidsutgang fra ffmpeg til en HTML5-klient ved hjelp av node.js, da det er en rekke variabler i spill, og jeg' t har mye erfaring i dette rommet, etter å ha brukt mange timer på å prøve forskjellige kombinasjoner. Mitt brukstilfelle er:
liveFFMPEG = child_process.spawn("ffmpeg", [
"-i", "rtsp://admin:[email protected]:554" , "-vcodec", "copy", "-f",
"mp4", "-reset_timestamps", "1", "-movflags", "frag_keyframe+empty_moov",
"-" // output to stdout
], {detached: false});
liveFFMPEG.stdout.pipe(resp);
Jeg har også brukt stream-hendelsen til å skrive FFMPEG-dataene til HTTP-svaret, men det gjør ingen forskjell.
xliveFFMPEG.stdout.on("data",function(data) {
resp.write(data);
}
Jeg bruker følgende HTTP-header (som også brukes og fungerer ved strømming av forhåndsinnspilte filer)
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
});
REDIGER 3: Fra og med IOS 10 støtter HLS fragmenterte mp4-filer. Løsningen nå er å lage fragmenterte mp4-filer med et DASH- og HLS-manifest. Lat som om flash, iOS9 og lavere og IE 10 og lavere ikke eksisterer.
EDIT 2: Som folk i kommentarfeltet påpeker, endrer ting seg. Nesten alle nettlesere vil støtte AVC/AAC-kodeker. iOS krever fortsatt HLS. Men via adaptere som hls.js kan du spille av HLS i MSE. Det nye svaret er HLS+hls.js hvis du trenger iOS. eller bare fragmentert MP4 (dvs. DASH) hvis du ikke trenger det.
Det er mange grunner til at video, og spesielt livevideo, er svært vanskelig. (Vær oppmerksom på at det opprinnelige spørsmålet spesifiserte at HTML5-video er et krav, men spørreren opplyste i kommentarfeltet at Flash er mulig. Så umiddelbart er dette spørsmålet misvisende).
Først vil jeg gjenta: DET FINNES INGEN OFFISIELL STØTTE FOR DIREKTESTRØMMING VIA HTML5. Det finnes hacks, men din erfaring kan variere.
EDIT: siden jeg skrev dette svaret har Media Source Extensions modnet, og er nå veldig nær ved å bli et levedyktig alternativ. De støttes i de fleste store nettlesere. IOS fortsetter å holde igjen.
Dernest må du forstå at Video on demand (VOD) og live video er svært forskjellige. Ja, begge deler er video, men problemene er forskjellige, og derfor er formatene forskjellige. Hvis for eksempel klokken på datamaskinen din går 1 % raskere enn den burde, vil du ikke merke det på VOD. Med live-video prøver du å spille av videoen før det skjer. Hvis du vil bli med i en pågående direktesendt videostrøm, trenger du dataene som er nødvendige for å initialisere dekoderen, så de må gjentas i strømmen eller sendes ut av båndet. Med VOD kan du lese begynnelsen av filen og søke til det punktet du ønsker.
Nå går vi litt dypere inn i materien.
Plattformer:
Kodeker:
Vanlige leveringsmetoder for live video i nettlesere:
Vanlige leveringsmetoder for VOD i nettlesere:
html5 video tag:
La oss se på hvilke nettlesere som støtter hvilke formater
Safari:
Firefox
IE
Chrome
MP4 kan ikke brukes til live video (OBS: DASH er en overbygning av MP4, så ikke bli forvirret av det). MP4 er delt opp i to deler: moov og mdat. mdat inneholder de rå lyd- og videodataene. Men den er ikke indeksert, så uten moov er den ubrukelig. Moov inneholder en indeks over alle dataene i mdat. Men på grunn av formatet kan den ikke flates ut før tidsstemplene og størrelsen på HVER frame er kjent. Det kan være mulig å konstruere en moov som 'fibrer' rammestørrelsene, men det er veldig sløsing med båndbredde.
Så hvis du vil levere overalt, må vi finne minste fellesnevner. Du vil se at det ikke finnes noen LCD her uten å ty til flash. eksempel:
Det nærmeste man kommer en LCD, er å bruke HLS for iOS-brukere og flash for alle andre. Min personlige favoritt er å kode HLS, og deretter bruke flash til å spille av HLS for alle andre. Du kan spille av HLS i flash via JW player 6, (eller skrive din egen HLS til FLV i AS3 som jeg gjorde).
Snart vil den vanligste måten å gjøre dette på være HLS på iOS/Mac og DASH via MSE alle andre steder (dette er hva Netflix vil gjøre snart). Men vi venter fortsatt på at alle skal oppgradere nettleserne sine. Du vil sannsynligvis også trenge en egen DASH/VP9 for Firefox (jeg kjenner til open264; den suger. Den kan ikke gjøre video i hoved- eller høyprofil. Så den er for øyeblikket ubrukelig).
Takk til alle, spesielt szatmary, da dette er et komplekst spørsmål med mange lag, som alle må fungere før du kan streame live video. For å avklare det opprinnelige spørsmålet mitt og HTML5-videobruk vs flash - min brukssak har en sterk preferanse for HTML5 fordi det er generisk, enkelt å implementere på klienten og fremtiden. Flash kommer langt etter, så la oss holde oss til HTML5 i dette spørsmålet.
Jeg lærte mye gjennom denne øvelsen og er enig i at live streaming er mye vanskeligere enn VOD (som fungerer bra med HTML5-video). Men jeg fikk dette til å fungere tilfredsstillende for mitt brukstilfelle, og løsningen viste seg å være veldig enkel, etter å ha jaktet på mer komplekse alternativer som MSE, flash, forseggjorte bufferordninger i Node. Problemet var at FFMPEG ødela den fragmenterte MP4-filen, og jeg måtte justere FFMPEG-parametrene, og standard node stream pipe-omdirigering over http som jeg opprinnelig brukte, var alt som trengtes.
I MP4 er det et 'fragmenterings' -alternativ som bryter mp4 i mye mindre fragmenter som har sin egen indeks og gjør mp4 live streaming-alternativet levedyktig. Men det er ikke mulig å søke tilbake i strømmen (OK for mitt bruksområde), og senere versjoner av FFMPEG støtter fragmentering.
Legg merke til at timing kan være et problem, og med min løsning har jeg en forsinkelse på mellom 2 og 6 sekunder forårsaket av en kombinasjon av remuxing (FFMPEG må i praksis motta livestrømmen, remuxe den og deretter sende den til node for servering over HTTP). Det er ikke så mye å gjøre med dette, men i Chrome prøver videoen å ta igjen så mye den kan, noe som gjør videoen litt hakkende, men mer aktuell enn i IE11 (min foretrukne klient).
I stedet for å forklare hvordan koden fungerer i dette innlegget, kan du ta en titt på GIST med kommentarer (klientkoden er ikke inkludert, det er en standard HTML5-videotagg med node http-serveradressen). GIST finner du her: https://gist.github.com/deandob/9240090
Jeg har ikke vært i stand til å finne lignende eksempler på dette brukstilfellet, så jeg håper forklaringen og koden ovenfor kan hjelpe andre, spesielt siden jeg har lært så mye fra dette nettstedet og fortsatt anser meg selv som nybegynner!
Selv om dette er svaret på mitt spesifikke spørsmål, har jeg valgt szatmary' s svar som det aksepterte, da det er det mest omfattende.
Dette er en svært vanlig misforståelse. Det finnes ingen støtte for live HTML5-video (bortsett fra HLS på iOS og Mac Safari). Du kan kanskje 'hacke' det ved hjelp av en webm-container, men jeg forventer ikke at det støttes av alle. Det du er ute etter, er inkludert i Media Source Extensions, der du kan mate fragmentene til nettleseren ett om gangen. men du må skrive litt javascript på klientsiden.