I started playing with WebCodecs API. I try to create mp4 video from set of jpg images. Starting with something simple, I'm trying to create an mp4 from one jpg image. When the output callback is invoked it is saving video chunk into the mp4 file.
const downloadVideo = (data) => {
console.log("downlaodVideo data:" + data);
const link = document.createElement("a");
const file = new Blob([ Uint8Array.from( data ) ] , {type: "application/octet-stream"});
link.href = URL.createObjectURL(file);
link.download = "video.h264";
link.click();
URL.revokeObjectURL(link.href);
};
$(document).ready(async function () {
const videoEncoder = new VideoEncoder(
{
async output(chunk, metadata) {
console.log("encoder queue:" + videoEncoder.encodeQueueSize);
console.log("timestamp:" + chunk.timestamp + " counter:" + counter);
console.log("length:" + chunk.byteLength);
console.log("video chunk type:" + chunk.type);
console.log("duration:" + chunk.duration)
console.log(JSON.stringify(metadata));
console.log("decoder config:" + metadata.decoderConfig );
var myMetadata;
var videoBlob;
if (metadata.decoderConfig) {
//# save the decoder's description/config ...
//# is SPS and PPS metadata needed by players to display H.264)
console.log("decoder config description:" + metadata.decoderConfig.description);
myMetadata = new Uint8Array( metadata.decoderconfig.description );
}
videoBlob = new ArrayBuffer(chunk.byteLength);
chunk.copyTo(videoBlob);
//# combine the two arrays (in the shown order of appearance)
var outputBytes = [...myMetadata, ...videoBlob];
downloadVideo(outputBytes);
},
error(error) {
console.log(output_Bytes);
},
}
);
const encoderConfig = {
codec: "avc1.42001E",
avc: { format: 'annexb' },
height: 480,
width: 640,
framerate: 1,
latencyMode: "realtime",
bitrate: 2_000_000, // 2 Mbps
};
const support = await VideoEncoder.isConfigSupported(encoderConfig);
if (support.supported) {
console.log("Video Encoder configured!");
videoEncoder.configure(encoderConfig );
}
else {
console.error("Video codec not supported!");
}
$('#create_movie').click( function(ev) {
const myImage = new Image();
myImage.src = "samples/pic0.jpg";
var imageBitmap = null;
var imageBitmapPromise = null;
myImage.onload = () => {
imgContext.drawImage(myImage,0,0);
imageBitmapPromise = createImageBitmap(myImage);
imageBitmap = imageBitmapPromise.then( result => {
const ms = 1_000_000; // 1µs
const fps = 10;
return new VideoFrame(result, {
timestamp: (ms * 1) / fps,
duration: ms / fps
},false);
}).then(vidFrame => {
console.log("imageBitmap:" + vidFrame);
console.log("video frame timestamp:" + vidFrame.timestamp);
console.log("format:" + vidFrame.format);
videoEncoder.encode(vidFrame, { keyFrame: true });
vidFrame.close();
});
}
});
}
Unfortunately, the video opens with an error message: The file you trying to play is empty file I generated mp4 from the same jpg file with ffmpeg tool:
ffmpeg -i pic%d.jpg -vcodec mpeg4 test.mp4
The structure of both files is quite different:
On the left is video generated by ffmpeg. It contains some metadata that are missing in vido file generated by my code. So my question is: how to properly generate video file using WebCodecs API?

WebCodecs doesn't do any muxing into containers like MP4 or AVI etc. It only gives the raw encoded frames (video or audio) and then the code-writer themselves will decide on an output container format (if needed).
Are you assuming you need MP4 to display it?
If yes: H.264 is playable as it is, since it's a video format.
Or you know for sure that you need MP4 output (eg: for HTML5 playback)?
If yes: Good luck. Not hard but very tedious to double-check everything.
Is it for preview purposes?
Use a player like VLC to play your saved H.264 file If you simply want to check that your code worked fine. VLC runs on desktop (so just drag your file into its window to check the visuals).
For online playback you can either find a JS-ready muxer like: JMuxer as shown in the code below, or else enjoy learning about MP4 structure then write the code. For writing own MP4 bytes I tried to explain a starting point on another Question, but they never responded.
Outside of webcodecs, you can just draw images into canvas then encode into MP4 using H.264-MP4-Encoder.
You first need a correctly encoded H.264 file or no player will accept it.
(see below for fixes to your code)...
To encode a playable raw H.264:
You need to set
Annex-Bas the output formatTo encode your H.264 contained inside MP4 (using JMuxer):