React
by wuct
HTML
<div id="app"></div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
React
//import { Muxer, ArrayBufferTarget } from "mp4-muxer";
//import { useState, useRef, useEffect, useCallback } from "react";
export default function App() {
const [videoSrc, setVideoSrc] = useState(null);
const videoRef = useRef();
useEffect(() => {
videoRef.current?.load();
}, [videoSrc]);
const handleChange = useCallback((e) => {
console.log("start convertGifToMp4");
const file = e.target.files[0];
const filereader = new FileReader();
filereader.onload = (res) => {
// TODO: check why it's loaded twice sometimes
console.log("file one load", res);
convertGifToMp4(res.target.result).then((bytes) => {
console.log("mp4 result", bytes);
const file = new Blob([bytes], { type: "video/mp4" });
const url = URL.createObjectURL(file);
setVideoSrc(url);
});
};
filereader.readAsArrayBuffer(file);
}, []);
async function convertGifToMp4(data) {
const imageDecoder = new ImageDecoder({ data, type: "image/gif" });
await imageDecoder.completed;
await imageDecoder.tracks.ready;
const frameCount = imageDecoder.tracks.selectedTrack.frameCount;
console.log("imageDecoder", imageDecoder);
// decode first frame to obtain gif resolution
const firstFrame = await imageDecoder.decode({ frameIndex: 0 });
const { displayWidth, displayHeight } = firstFrame.image;
// H264 only supports even sized frames
const width = displayWidth % 2 === 0 ? displayWidth : displayWidth - 1;
const height = displayHeight % 2 === 0 ? displayHeight : displayHeight - 1;
// https://github.com/Vanilagy/mp4-muxer?tab=readme-ov-file#initialization
const muxer = new Muxer({
target: new ArrayBufferTarget(),
video: {
codec: "vp9",
width,
height,
},
fastStart: "in-memory",
});
const videoEncoder = new VideoEncoder({
output: (chunk, meta) => {
console.log("videoEncoder ouput", meta, chunk);
...