2016-05-20 11 views
6

Ich habe ein Binärdokument (mp4-Videodatei) in einer Datenbank (MarkLogic). Ich verwende die Node.js API der Datenbank, um das Dokument in Chunks zu streamen. Das Setup sieht wie folgt aus:Node.js/Express-Video-Streaming (HTTP 206 Teilinhalt)

html-Datei

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

Expressgut dann habe ich Setup eine Route, die den/Video/Griffe: param Route (in der Datenbank das Video die eindeutige Kennung hat, die der String '/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); 

Jetzt schlägt das obige natürlich fehl mit 'Fehler: Header können nach dem Senden nicht gesetzt werden.' Das ist alles fair und quadratisch. Aber ich kann mich nicht damit herumschlagen - der .stream ('chunked') Aufruf zwingt die Datenbank, das Dokument in Chunks abzufragen, und ich sehe diese Chunks ganz gut, aber wie kann ich eine 206 für den Browser zurückgeben? Ich kann es nicht in der .on ("Daten") tun, während Daten gestreamt werden, so dass die Kopfzeile mehrmals gesendet werden würde. Ich denke, welche Datenbank ich verwende ist nicht wirklich relevant - ich würde gerne das Konzept verstehen oder zumindest sehen, was ich falsch mache.

Jede Hilfe wird geschätzt. Alle Beispiele und andere Diskussionen, die ich gesehen habe, dass Video mit Node.js streamen, lesen die Videodatei von der Festplatte.

Update

eine Änderung des Codes zu machen erlaubt nun FF das Video aber nicht Chrome zu spielen:

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

Es gibt keine Fehler in Chrome-Konsole. Hier sind die Kopfdetails - beachten Sie, dass es zwei Anfragen für die mp4-Datei:

1.

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 

2.

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

Haben Sie bewiesen, dass Ihr Code oben funktioniert, indem Sie von der Festplatte lesen? Ich schlage das als ersten Schritt zur Fehlerbehebung vor. Sobald Sie die Rückseite brechen auf dem der allgemeine Code ist Sound, dann fügen Sie die DB-Schritte zurück in. –

+0

Gute Frage! Ich würde sagen, dass Sie writeHead nicht anrufen sollten, aber dass Sie in Express eindringen müssen, um Kopfzeile direkt zu schreiben. Sie können auch einen Blick auf diesen [code] (https://github.com/feross/webtorrent/blob/c85dd3b83bdbd7fcbbb32c65a080b7011e4daeder/lib/server.js) werfen, von dem ich weiß, dass er ein Video mit 206 Antworten streamen kann, er wird in peerflix verwendet . siehe auch https://gist.github.com/paolorossi/1993068 –

+0

Sie müssen wahrscheinlich nicht alle Chunk-Sachen. Setzen Sie die Header manuell: 'res.status (206);'. Dann pipe einfach die Antwort: 'let stream = db.yourChunkStuff(); stream.pipe (res); '. Auf einem Telefon hier kann man also nicht testen, also nur in einen Kommentar setzen. – Zlatko

Antwort

4

Die auf (‚Daten‘) Rückruf könnte immer einen Verschluss über eine isFirstChunk -Variable, die mit true initialisiert wird und einen Test hat, der, wenn isFirstChunk wahr ist, die Header ausgibt und isFirstChunk auf false setzt.

Es wäre vorzuziehen, den Strom wenn möglich zu leiten. npm könnte eine Stream-Bibliothek (vielleicht sogar through2()?) anbieten, die ein Ereignis hat, wenn die ersten Daten ankommen.

Längerfristig könnten Sie vernünftigerweise ein RFE für ein Ereignis am Anfang eines Streams einreichen.

der Hoffnung, dass hilft,

3

Sie höchstwahrscheinlich brauchen nicht das ganze Zeug Brocken. Set-Header manuell:

res.status(206); 

Dann einfach Rohr die Antwort:

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

Der einfachste Weg, Rohrströme ist.