Search code examples
node.jsvideo-streamingvideo-processingh.264

Create valid h264 from partial stream of h264 video data and wrap as Mp4


Lets say that I am reading from data stream, and that stream is sending the content of an h264 video feed. Given I read from that stream and I have some amount of data consisting of an indeterminate number of frames (NAL?). Given that i know the framerate, and size of the originating video, how would I go about converting this snippet into a mp4 that i could view? The video does not contain audio.

I want to do this using nodejs? My attempts to do so have produced nothing resembling a valid h264 file to convert into mp4. My thoughts so far were to strip any data preceding the first found start code in the data and feed that into a file and use ffmpeg (currently just testing in the command line) to convert the file to mp4.

What's the correct way to go about doing this?

ie. something like this (it's in Typescript but same thing)

//We assume here that when this while loop exist at least one full frame of data will have been read and written to disk
let stream: WriteStream = fs.createWriteStream("./test.h264")
while(someDataStream.available()) { //just an example not real code
    let data: Buffer = someDataStream.readSomeData() //just an example not a real method call
    let file = null;
    try {
        file = fs.statSync("./test.h264");
    } catch (error) {
        console.error(error)
    }

    if(!stream.writable) {
        console.error("stream not writable")
    } else if(file == null || file.size <= 0) {
      

        let index = data.indexOf(0x7C)
        console.log("index: " + index)
        if(index > 0) {
            console.log("index2: " + data.slice(index).indexOf(0x7c))
            stream.write(data.slice(index))
        }
    } else {
        stream.write(data)
    }
}

Solution

  • To handle a data stream, you'll need to emit fragmented MP4. Like all MP4, fMP4 streams begin with a preamble containing ftyp, moov, and styp boxes. Then each frame is encoded with a moof / mdat box pair.

    In order to generate a useful preamble from your H.264 bitstream, you need to locate a SPS / PPS pair of NALUs in the H264 data, to set up the avc1 box within the moov box. Those two NALUs are often immediately followed by an I-frame (a key frame). The first frame in a stream must be an I-frame, and subsequent ones can be P- or B- frames. E

    It's a fairly complex task involving lots of bit-banging and buffer-shuffling (those are technical terms ;-).

    I've been working on a piece of js code to extract H.264 from webm and put it into fmp4. It's not yet complete. It's backed up by another piece of code to decode the parts of the H264 stream that are needed to pack it properly into fMP4.

    I wish I could write, "here are the ten lines of code you need" but those formats (fMP4 and H264) aren't simple enough to make that possible.