I am sending buffer
from client to server and then save them as a blob
into an mp4 file like this :
async function saveIntoMp4(format) {
if (chunks.length) {
const options = recOptions.mimeType ? { type: recOptions.mimeType } : { type: "video/mp4" }
let blob = new Blob(chunks, options);
if (blob.size > 9999) {
console.log(`blob.size`, blob.size);
const buffer = Buffer.from(await blob.arrayBuffer());
try {
fs.writeFileSync( // writeFile
`${__dirname}/videos/1.mp4`,
buffer,
() => console.log("video saved!")
);
However I am not able to play the saved files remotely from the video
tag since the moov atom is not in the begining of the file or is missing altogether. I am saving most of my files in h264 encoding and I wonder if there is a way without using a third party library such as FFMPEG to add MOOV to the begining of my files and make them virtually playable.
"I wonder if there is a way without using a third party library such as FFMPEG to add MOOV to the begining of my files and make them virtually playable?"
Yes but you must be familiar with bytes handling...
About re-arranging the MOOV atom (if you have MP4 data)
(1) You will have to extract the MOOV atom's section from the last chunk as a separate Array.
To find the atom in last chunk, look for bytes/array slots with a sequence of letters for text "mdat".
Bytes are written in hex format (as String) and this looks like 6D 64 61 74
.
JS will read array in decimals (as Integer) not hex so same sequence looks like 109, 100, 97, 116
.
This means inside the array, find sequence [... 109, 100, 97, 116 ...]
so look for a decimal 109
(which is equivalent to byte 0x6D
) and check if next array slot has a decimal 100
itself followed by 97
and so on.
After finding start position of m-d-a-t sequence, the previous four array slots are the size so read those four bytes into temp variables (eg: tempA, tempB, tempC, tempD) and then concat as one 32-bit integer:
tempA = MP4_Bytes[ mdat_Start-3 ];
tempB = MP4_Bytes[ mdat_Start-2 ];
tempC = MP4_Bytes[ mdat_Start-1 ];
tempD = MP4_Bytes[ mdat_Start-0 ];
//# concat into one 32-bit integer
mdat_Size = ( tempA << 24 | tempB << 16 | tempC << 8 | tempD );
Now you have size of MOOV for cut/copy size.
A quick cheat is to just find start pos of m-d-a-t and copy from (start_pos - 4)
to also grab the four "size" bytes.
(2) Next you have to update your a/v Sample offsets inside the MOOV.
A simplified example: if at your chunk/file's end the MOOV was 100 bytes long and then you also had 3 video frames, at file's start, at offsets 0, 10 and 20... When you put MOOV in front then frame 1 is now pushed forward to a new position at offset 100 and frame 2 is now at 110 and frame 3 is now at 120 etc. The extracted MOOV header holds the original old offsets of frames as (0,10,20) so you simply update those numbers as (100, 110, 120) to account for new data in front of the 3 frames.
How to update offsets?
Try editing the STCO atom first. See configure MP4 time for some explanation. You edit all the STCO's listed chunk offsets by increasing their current listed size to become listed_size + (size_of_mdat + 4)
.
You will need to write the "size" number across four array slots (or spread over 4 bytes).
Test if the video plays.