视频标签仅在移动设备上调用一个字节的数据(Node.js)

video tag makes call for one byte of data only on mobile (Node.js)

本文关键字:字节 一个 标签 数据 js Node 移动 视频 调用      更新时间:2023-09-26

>我创建了一个节点服务器,它使用 gridfs 从 Mongo 数据库流式传输 mp4 视频。将视频流式传输到桌面浏览器时我没有问题,但是当我尝试流式传输到任何移动设备时,我只能看到视频播放器,但它无法播放。当我检查我的服务器日志时,我看到桌面版本调用视频的总字节数为 0,但在移动设备上,它只调用字节 0-1 然后停止,没有给出任何错误。

这是两个服务器端函数,在流式传输到 PC 浏览器时效果很好。

function StreamGridFile(req, res, GridFile) {
console.log("Request: " + req);
if (req.headers['range']) {
// Range request, partialle stream the file
console.log('Range Request');
var parts = req.headers['range'].replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : GridFile.length - 1;
var chunksize = (end - start) + 1;
console.log('Range ', start, '-', end);
res.writeHead(206, {
  'Content-Range': 'bytes ' + start + '-' + end + '/' + GridFile.length,
  'Accept-Ranges': 'bytes',
  'Content-Length': chunksize,
  'Content-Type': GridFile.contentType
});
// Set filepointer
GridFile.seek(start, function() {
  // get GridFile stream
  var stream = GridFile.stream();
  // write to response
  stream.on('data', function(buff) {
    // count data to abort streaming if range-end is reached
    // perhaps theres a better way?
    start += buff.length;
    if (start >= end) {
      // enough data send, abort
      GridFile.close();
      res.end();
    } else {
      res.write(buff);
    }
  });
  stream.on("end", function() {
    // Record the end was called
    GridFile.close()
    db.close(function() {
      counter--;
      console.log("closed db, counter: " + counter);
    });
  });
});
} else {
// stream back whole file
console.log('No Range Request');
var stream = GridFile.stream();
stream.pipe(res);
stream.on("end", function() {
  // Record the end was called
  gridfile.close();
  db.close(function() {
    counter--;
    //console.log("closed db, counter: " + counter);
  });
});
  }
}

这是第二个

     exports.streamVideo = function(req, res, id) {
      console.log("entered the stream video function");
      if (counter == 0) {
        console.log("counter = 0");
        db.open(function(err, db) {
  console.log("db open for video stream");
  counter++;
  console.log(counter);
  if (!err) {
    var gs = GridStore(db, ObjectID(id));
    gs.open(function(err, GridFile) {
      console.log("gridstore open");
      if (err) {
        res.writeHead(404, {
          'Content-Type': 'text/javascript'
        });
        res.end("Video not found");
        gs.close();
        db.close();
        return;
      }
      console.log("no error, entering StreamGridFile function");
      StreamGridFile(req, res, GridFile);
    });
  } else {
    res.writeHead(404, {
      'Content-Type': 'text/javascript'
    });
    res.end("database error");
    gs.close();
    db.close();
  }
})
     }
    }

我很确定错误属于此代码,因为我最初从静态文件流式传输视频,但后来转换为使用 mongo,那是它停止工作的时候。

试一试:

function StreamGridFile (req, res, GridFile) {
  console.log("Request: " + req);
  if (req.headers['range']) {
    // Range request, partialle stream the file
    console.log('Range Request');
    var parts = req.headers['range'].replace(/bytes=/, "").split("-");
    var maxIdx = GridFile.length - 1;
    var start = parseInt(parts[0], 10);
    var end = parseInt(parts[1], 10);
    if (isInvalidRange(start, end, maxIdx)) {
      return res.writeHead(416, {
        'Accept-Ranges': 'bytes',
        'Content-Type': GridFile.contentType,
        'Content-Range': 'bytes */' + GridFile.length,
      }).end();
    }
    if (end > maxIdx || end !== end) {
      end = maxIdx
    }
    var bytesToSend = end - start + 1;
    res.writeHead(206, {
      'Accept-Ranges': 'bytes',
      'Content-Type': GridFile.contentType,
      'Content-Range': 'bytes ' + start + '-' + end + '/' + GridFile.length,
      'Content-Length': bytesToSend
    });
    // Set filepointer
    GridFile.seek(start, function() {
      // get GridFile stream
      var stream = GridFile.stream(true);
      // write to response
      stream.on('data', function(buff) {
        if (buff.length > bytesToSend) {
          buff = buff.slice(0, bytesToSend)
        }
        res.write(buff);
        bytesToSend -= buff.length;
        if (bytesToSend <= 0) {
          // enough data send, abort
          GridFile.close();
          db.close(function() {
            counter--;
            console.log("closed db, counter: " + counter);
          });
          res.end();
        }
      });
    });
  } else {
    // stream back whole file
    console.log('No Range Request');
    res.header('Accept-Range', 'bytes');
    res.header('Content-Type', GridFile.contentType);
    var stream = GridFile.stream(true);
    stream.pipe(res);
    stream.on('end', function(){
      GridFile.close();
      db.close(function() {
        counter--;
        console.log("closed db, counter: " + counter);
      });
    });
  }
}
function isInvalidRange (start, end, maxIdx) {
  return start !== start  // NaN
      || start < 0
      || end < start
      || start > maxIdx
}

这显然无法处理多字节范围请求(其中Range标头看起来像bytes=2048-4095,4096-6143),但它应该能够处理正常的字节范围请求。