2016-05-20 14 views
6

Ho un documento binario (file video mp4) in un database (MarkLogic). Sto usando l'API Node.js del database per lo streaming del documento in blocchi. La configurazione assomiglia a questo:Node.js/streaming video Express (contenuto parziale HTTP 206)

file html

<video controls="controls" width="600"> 
    <source src="/video/myvideo.mp4" type="video/mp4"> 
</video> 

in veloce Ho poi messa a punto di un percorso che gestisce l'/ video /: percorso param (nel database il video ha l'identificatore univoco, che è la stringa '/video/myvideo.mp4')

Node.JS

// I'm only showing the relevant things in here 

const serveVideo = (req, res) => { 
    var stream = db.documents.read('/gopro/malta.mp4').stream('chunked'); 

    var chunks = []; 
    var chunkBytes = 0; 
    var start = 0; 
    stream.on('data', (chunk) => { 
    var headers; 
    var range = req.headers.range; 
    var total = 214335483; //total length of vid in bytes 

    if (range) { 
     var chunkSize = chunk.length; 
     // (start === 0) ? start = 0 : start += chunkBytes; 
     if (chunkBytes === 0) { 
     start = 0 
     } else { 
     start = chunkBytes + 1 
     } 
     chunkBytes += chunkSize; 

     headers = { 
     'Content-Range': 'bytes ' + start + '-' + chunkBytes + '/' + total, 
     'Accept-Ranges': 'bytes', 
     'Content-Length': chunkSize, 
     'Content-Type': 'video/mp4' 
     }; 
     res.writeHead(206, headers); 
     chunks.push(chunk); 
    } 
    }); 
    stream.on('end',() => { 
    var allChunks = Buffer.concat(chunks); 
    res.end(allChunks); 
    }); 
}); 


router.route('/video/:uri').get(serveVideo); 

Ora, ovviamente, quanto sopra non funziona con "Errore: impossibile impostare le intestazioni dopo che sono state inviate". che è tutto giusto e quadrato. Ma non riesco a capirlo: la chiamata .stream ("chunked") costringe il database a recuperare il documento in blocchi e vedo bene quei blocchi, ma come posso restituire un 206 per il browser? Non posso farlo in .on ('data') dato che i dati vengono trasmessi in streaming in modo che l'intestazione venga inviata più volte. Credo che il database che sto usando non sia davvero rilevante - mi piacerebbe capire il concetto, o almeno vedere cosa sto facendo male.

Qualsiasi aiuto è apprezzato. Tutti gli esempi e le altre discussioni che ho visto in streaming video utilizzando Node.js stanno leggendo il file video dal disco.

aggiornamento

Fare una modifica al codice di ora permette di FF per riprodurre il video, ma non Chrome:

let stream = db.documents.read({uris:'/gopro/malta.mp4'}).stream('chunked'); 
stream.pipe(res); 

Non ci sono errori nella console di Chrome. Ecco i dettagli di intestazione - notare che ci sono due richieste per il file mp4:

prima

Response Headers 
Connection:keep-alive 
Date:Sat, 21 May 2016 17:05:30 GMT 
Transfer-Encoding:chunked 
X-Powered-By:Express 

Request Headers 
view source 
Accept:*/* 
Accept-Encoding:identity;q=1, *;q=0 
Accept-Language:en-US,en;q=0.8,hu;q=0.6,ro;q=0.4,it;q=0.2 
Cache-Control:no-cache 
Connection:keep-alive 
Cookie:__distillery=v20150227_a8e22306-65b3-4c2e-9a8a-159e308156ad; __smToken=7nYU8NYQY15mPowjjCZsS5D3 
DNT:1 
Host:localhost:8080 
Pragma:no-cache 
Range:bytes=0- 
Referer:http://localhost:8080/ 
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36 

secondo

Response Headers 
Connection:keep-alive 
Date:Sat, 21 May 2016 17:05:31 GMT 
Transfer-Encoding:chunked 
X-Powered-By:Express 

Request Headers 
view source 
Accept:*/* 
Accept-Encoding:identity;q=1, *;q=0 
Accept-Language:en-US,en;q=0.8,hu;q=0.6,ro;q=0.4,it;q=0.2 
Cache-Control:no-cache 
Connection:keep-alive 
Cookie:__distillery=v20150227_a8e22306-65b3-4c2e-9a8a-159e308156ad; __smToken=7nYU8NYQY15mPowjjCZsS5D3 
DNT:1 
Host:localhost:8080 
Pragma:no-cache 
Range:bytes=28- 
Referer:http://localhost:8080/ 
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36 
+0

Hai provato che il tuo codice sopra funziona tramite la lettura dal disco? Lo suggerisco come il primo passo per la risoluzione dei problemi. Una volta che si rompe la parte posteriore che il codice generale è valido, quindi aggiungere nuovamente i passaggi DB. –

+0

Buona domanda! Direi che non dovresti chiamare writeHead, ma che dovrai scavare direttamente in express per scrivere header. Puoi anche dare un'occhiata a questo [codice] (https://github.com/feross/webtorrent/blob/c85dd3b83bdbd7fcbbb32c65a080b7011e4daede/lib/server.js) che so può riprodurre in streaming un video con 206 risposte, è usato in peerflix . vedi anche https://gist.github.com/paolorossi/1993068 –

+0

Probabilmente non hai bisogno di tutte le cose chunk. Imposta manualmente le intestazioni: 'res.status (206);'. Quindi inserisci semplicemente la risposta: 'let stream = db.yourChunkStuff(); stream.pipe (res); '. Su un telefono qui, quindi, non è possibile testare, quindi inseriscilo ora solo in un commento. – Zlatko

risposta

4

L'on callback ('Dati') potrebbe sempre avere una chiusura su una variabile isFirstChunk inizializzata su true e con un test che, se isFirstChunk è true, emette le intestazioni e imposta isFirstChunk su false.

Sarebbe preferibile collegare il flusso, se possibile. npm potrebbe offrire una libreria di stream (forse anche through2()?) che ha un evento quando arrivano i primi dati.

Per il lungo termine, è possibile archiviare ragionevolmente un RFE per un evento all'inizio di un flusso.

Sperando che aiuta,

3

Molto probabilmente non hanno bisogno di tutta la roba pezzo. Impostare le intestazioni manualmente:

res.status(206); 

Poi basta tubo la risposta:

let stream = db.yourChunkStuff(); 
stream.pipe(res); 

Il modo più semplice per i flussi è tubi.

Problemi correlati