How to get a video stream from google could storage object that is able to seek

Viewed 830

I'm streaming a video file from a cloud storage bucket in an express.js server and was able to successfully pipe that stream to a video element in the frontend. However, since the video content is now loaded progressively, I can't seek through the loaded video.

My node.js code for getting a video stream from a cloud storage object is as follows.

async function getVideoStream(gcloudFileName,res){
  const bucket = storage.bucket(process.env.GCS_BUCKET);
  const remoteFile = bucket.file(gcloudFileName);
  return remoteFile.createReadStream().pipe(res)
}

How can I make this video stream possible to seek so that users can seek through the video on the frontend? Helpful suggestions are highly appreciated.

EDIT:

I tried with @Rafael's answer and got it working up to some extent, but now the problem is the stream stops after delivering the first few chunks of the video. Also at the same time, the video also stops playing.

enter image description here

1 Answers

You need to use ranged requests, as mentioned in @szatmary comment, so that the server can send chunks of the file at a time instead of the whole thing, you can find a complete explanation in this article, but applied to your code you can do the following:

async function getVideoStream(req,res){
  const range = req.headers.range;
  if (!range) {
    res.status(400).send("Requires Range header");
  }
  const bucket = storage.bucket(process.env.GCS_BUCKET);
  // I added the file name to your request's body
  const remoteFile = bucket.file(req.body);

  //calculates the chunck to be sent based on the video size
  const videoSize = remoteFile.getMetadata().size;
  const CHUNK_SIZE = 10 ** 6; // 1MB
  const start = Number(range.replace(/\D/g, ""));
  const end = Math.min(start + CHUNK_SIZE, videoSize - 1);

  // Create headers
  const contentLength = end - start + 1;
  const headers = {
    "Content-Range": `bytes ${start}-${end}/${videoSize}`,
    "Accept-Ranges": "bytes",
    "Content-Length": contentLength,
    "Content-Type": "video/mp4",
  };

  // HTTP Status 206 for Partial Content
  res.writeHead(206, headers);

  //returns the chunk that you want
  return remoteFile.createReadStream({ start, end }).pipe(res)
}
Related