Oyosied
Oyosied

Reputation: 63

Streaming MP4 using GridFS,NodeJS and react - getting 206 partial content error

I am working on my streaming project for quite sometime. Everything works great, however I am getting 206 err partial content when streaming is done for large MP4 files. I do understand why is that I researched a ton and it appears to be a bug in NodeJS compression or something. I uploaded the entire project to git-hub.

https://github.com/oyosied/cat-flix-frontend

https://github.com/oyosied/cat-flix-backend

I do see from debugging that for large files , when stream starts in controllers/videoStream.js getVideoStream . Is that the start in the Range header is equal to the end. Which is weird and I can't figure out why. I'll be really glad if anyone is familiar with this issue and how it's possible to fix this, I tried changing ReactPlayers PlyR, VideoJS etc and it doesn't do the trick.

exports.getVideoStream = (req, res, next) => {
  const DBConn = getDataBaseConnection("getVideoStream");
  DBConn().conn.client.connect(function (error, client) {
    if (error) {
      res.status(500).json(error);
      return;
    }

    // Check for range headers to find our start time
    const range = req.headers.range;
    if (!range) {
      res.status(400).send("Requires Range header");
    }

    const db = client.db("CatFlix");
    // GridFS Collection

    db.collection("VideoFiles.files").findOne(
      { _id: mongoose.Types.ObjectId(req.params.id) },
      (err, video) => {
        if (!video) {
          res.status(404).send("Video is not found");
          return;
        }
        console.log(video);
        // Create response headers
        const videoSize = video.length;
        const start = Number(range.replace(/\D/g, ""));
        const end = videoSize - 1;
        let 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);

        // Get the bucket and download stream from GridFS
        const bucket = new mongodb.GridFSBucket(db, {
          bucketName: "VideoFiles",
        });

        const downloadStream = bucket.openDownloadStream(video._id, {
          start: start,
          end: end,
        });

        // Finally pipe video to response
        console.log(
          streamCounter,
          " start ",
          start,
          " end ",
          end,
          "content-length",
          contentLength,
          "video size",
          videoSize
        );
        streamCounter++;

        downloadStream.pipe(res);
      }
    );
  });
};

Most likely and issue with the streaming function and the range header which passes start with max value and not 0. Example video length is 2:17 seconds start value is 0 and end is 164923. This mp4 is ~6mb. When I try to stream a video of ~45mb start value is 4178967 end value 4178967 right from the begining.

Upvotes: 0

Views: 798

Answers (1)

Oyosied
Oyosied

Reputation: 63

I was missing plus one in

const downloadStream = bucket.openDownloadStream(video._id, {
          start: start,
          end:end +1 // was "end: end,"
        });

Apparently this array's end is not -1 and since I subtracted -1 above for the range header it gave a partial content error.

Upvotes: 2

Related Questions