Search code examples
javascripthtml5-videowebapimediastream

Native browser method for compressing video / audio before uploading?


I'm pretty sure the current answer is no but is there a built in way for browsers to compress video / audio? Perhaps there is a hack as I'm sure browsers will have access to compression libraries. Maybe something like

If there is no way currently, perhaps somebody could link to the spec proposal if there is one.


Solution

  • Currently, there isn't a built in browser API for compressing existing video or audio files on the client side. However, you can compress through a few workarounds:

    1. Using the MediaRecorder API

    This API is primarily for recording media streams, but you can specify codecs and bitrates to control the size and quality. It is mainly made for capturing in a compressed format than compressing existing files.

    const options = { mimeType: 'video/webm; codecs=vp9', bitsPerSecond: 1000000 };
    const mediaRecorder = new MediaRecorder(stream, options);
    

    2. Manipulating video frames with Canvas API

    You can draw video frames onto a canvas at a lower res and theb capture this as a new video stream. This method can reduce file size but is less efficient for high quality or long videos.

    video.onplay = () => {
      const canvas = document.createElement('canvas');
      canvas.width = video.videoWidth / 2; // Reduce resolution
      canvas.height = video.videoHeight / 2;
      const ctx = canvas.getContext('2d');
    
      function drawFrame() {
        ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
        requestAnimationFrame(drawFrame);
      }
    
      drawFrame();
    };
    

    3. WebAssembly and JavaScript Libraries

    For more heavy-duty compression, you can use libraries compiled to WebAssembly, like ffmpeg.js. These are more resource-intensive and may not be ideal for all scenarios.

    - Example using FFmpeg.js:
    import { FFmpeg } from '@ffmpeg/ffmpeg';
    
    async function compressVideo(inputVideoPath, outputVideoPath) {
        const ffmpeg = new FFmpeg();
        await ffmpeg.load();
    
        // Writing the input file to the FFmpeg file system
        await ffmpeg.writeFile(inputVideoPath, await fetchFile(inputVideoPath));
    
        // Execute FFmpeg command for compression
        // Example: ffmpeg -i input.mp4 -vcodec libx264 -crf 28 output.mp4
        await ffmpeg.exec(['-i', inputVideoPath, '-vcodec', 'libx264', '-crf', '28', outputVideoPath]);
    
        // Read the compressed file from FFmpeg file system
        const data = await ffmpeg.readFile(outputVideoPath);
    
        // Handle the compressed file (e.g., download or display in the browser)
        // ...
    }
    
    // Call the function with the appropriate file paths
    compressVideo('input.mp4', 'compressed_output.mp4');
    

    Ressources: