потоковое видео в nodejs через модуль fs - PullRequest
0 голосов
/ 15 января 2020

Я хочу транслировать видео в node.js через модуль fs, и я попробовал следующий код.

app.get('/video', function(req, res) {
  const path = 'assets/sample.mp4'
  const stat = fs.statSync(path)
  const fileSize = stat.size
  const range = req.headers.range
  if (range) {
    const parts = range.replace(/bytes=/, "").split("-")
    const start = parseInt(parts[0],10);
    const end = parts[1] ? parseInt(parts[1],10) : fileSize-1
    const chunksize = (end-start)+1
    const file = fs.createReadStream(path, {start, end})
    const head = {
      'Content-Range': `bytes ${start}-${end}/${fileSize}`,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunksize,
      'Content-Type': 'video/mp4',
    }
    res.writeHead(206, head)
    file.pipe(res)
  } else {
       const head = {
         'Content-Length': fileSize,
         'Content-Type': 'video/mp4',
       }
       res.writeHead(200, head)
       fs.createReadStream(path).pipe(res)
  }
})

Размер моего видео "sample.mp4": 1055736 байт, что составляет 1 МБ. Но когда я запустил код, я обнаружил, что при запуске переменная start равна 0, переменная end равна 1055735 и chunksize равна 1055736. И если вы посмотрите на заголовок Content-Range , который при запуске будет равняться приведенному ниже значению.

Content-Range: 'байтов 0-1055735 / 1055736'

Я хочу передать мой поток видео по частям, а не ждать загрузки всего видео. Но я думаю, что приведенный выше код не будет делать то же самое.

Может кто-нибудь сказать, пожалуйста, этот код правильный для потокового видео?

Заранее спасибо!

1 Ответ

0 голосов
/ 17 января 2020

Ваш код в порядке, за исключением одного: обычно браузер отправляет вам Range: bytes=0- в запросах на видео. Из этого заголовка ваш код

const start = parseInt(parts[0],10);
const end = parts[1] ? parseInt(parts[1],10) : fileSize-1

дает вам start === 0 и end === fileSize-1 и chunksize размера файла. Потому что parts[1] всегда ложно. Таким образом, вы решают отправить файл одним большим фрагментом, а не браузером. Браузер готов к приему 206 Partial Content, но вы его не отправляете. Попробуйте

const preferred_chunksize = 100000
let end = parts[1] ? parseInt(parts[1],10) : start + preferred_chunksize
if( end > fileSize-1 ) end = fileSize-1
const chunksize = end-start+1

preferred_chunksize может быть любым от 1 до fileSize, в зависимости от условий вашей сети. Я пытался preferred_chunksize = 1000 - это медленно. Я не пробовал preferred_chunksize = 1 - потому что это будет чрезвычайно медленно и приведет к миллионам запросов. preferred_chunksize от 100 000 до 10 000 000 выглядит приемлемым.

Но, на самом деле, если вы попробуете свой код на большом файле, вы не заметите чрезмерного использования памяти, и браузеры начнут воспроизводить ваши видеофайл сразу, без ожидания

загрузки всего видео

Даже если вы пропустите часть end все вместе (как это уже сделано в вашей версии кода), и упростите свой код, используя:

const end = fileSize-1
const chunksize = end-start+1

это будет делать.
И, как я знаю из исходной версии вашего вопроса, вы пишете учебник, так что для ваши цели это будет хорошо.

PS. И, конечно же, в рабочем коде лучше проверить, не искажен ли заголовок Range

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...