Is it possible to create new mp4 file from a single streaming byte range chunk?

MP4 files are structured with boxes. Two main of them being moov and mdat (general case of non-fragmented MP4):

  • moov box: contains other boxes :) - each of them contains information about the encoded data present in the mdat box (moov = metadata about the MP4 file). Typical metadatas are duration, framerate, codecs information, reference to the video/audio frames ...
  • mdat box: contains the actual encoded data for the file. It can come from various codecs and includes audio and video data (or only one of them if it happens to be). For H264 NAL units are contains within the mdat box.

The moov box is (should be) at the beginning of the file for MP4 file web delivery so if you write a byte range request from 0 to XX you will likely get the whole moov box + a certain amount of mdat data. Hence the file can be played up to a certain point. If you byte range from YY to XX chances are you will not get a decent moov box but a lot of mdat which as such cannot be used unless they are repack in a MP4 file with a proper moov box referencing information about the "cut" mdat.

It is possible to recreate a valid MP4 file from a byte range chunk but it requires an advanced knowledge of the MP4 file format structure (you need to retrieve the moov box as well to make it bearable). MP4 file format is based on ISO base media file format - that was specified as ISO/IEC 14496-12 (MPEG-4 Part 12).

I know 2 libs that could help doing what you want: one in PHP and one in Java. I do not know if such a lib exists for node.js (I guess it could be ported). Even if you do not use them the 2 libs above contain valuable information about the subject.

To provide an answer to your question you could tackle the issue with a different angle. Knowing which part of the file you want in milliseconds you could execute an ffmpeg command to splice the full-length MP4 file server-side into a smaller one and then do what you need with this new smaller MP4 file (as so you do not need to download unnecessary data on the client).

ffmpeg command for that is (in this case cut at 1 minute from beginning of file):

ffmpeg -i input.mp4 -ss 00:00:00.000 -t 00:01:00.000 -c:a copy -c:v copy output.mp4

See this post for more info on the above command line

This is done pretty fast as the MP4 file structure is just re-organised with no re-transcoding.

EDIT: Or can I use ffmpeg on a remote file and create the new clip locally?

ffmpeg -ss 00:01:00.000 -i "http://myfile.mp4" -t 00:02:00.000 -c:a copy -c:v copy output.mp4

Assuming you have ffmpeg on your client (app/web) if you run the above command ffmpeg will fetch the mp4 to the input URL then seek to 1 min and cut 2 min from there and so write the generated content to output.mp4 locally (without downloading the full file of course).

ffmpeg needs to be built with support for http protocol input (which you will find in most binaries). You can read here for further information on where to place the -ss parameter (pros/cons).