Happy Dog
Happy Dog

Reputation: 1

How to merge two webm videos using Webcodecs API?

Multiple small video files are played like a single video in video tag using mediasource buffer. I would like to create them as a single video file if export option is desired. For that I would like to use WebCodecs API. Help is appreciated.

Tried much but getting different errors in different browsers. (like "encoder is undefined" in firefox, "Failed to execute 'decode' on 'VideoDecoder': A key frame is required after configure() or flush()." in chrome.

async function fetchVideoData(videoUrl) {
  const response = await fetch(videoUrl);
  if (!response.ok) {
      throw new Error(`Failed to fetch video: ${response.statusText}`);
  }
  return response.arrayBuffer();
}

async function mergeWebMVideos(videoUrls) {
  const encodedChunks = [];
  let encoder;

  const initEncoder = (width, height) => {
      encoder = new VideoEncoder({
          output: (chunk) => {
              encodedChunks.push(chunk);
          },
          error: (e) => {
              console.error('Encoder error:', e);
          }
      });

      const config = {
          codec: 'vp8',
          width: width,
          height: height,
          bitrate: 4_000_000,
      };
      encoder.configure(config);
  };

  for (const videoUrl of videoUrls) {
      const videoData = await fetchVideoData(videoUrl);

      const decoder = new VideoDecoder({
          output: (frame) => {
              if (!encoder) {
                  initEncoder(frame.codedWidth, frame.codedHeight);
              } else {
                  if (frame.codedWidth !== encoder.width || frame.codedHeight !== encoder.height) {
                      encoder.configure({
                          codec: 'vp8',
                          width: frame.codedWidth,
                          height: frame.codedHeight,
                          bitrate: 4_000_000,
                      });
                  }
              }

              encoder.encode(frame);
              frame.close();
          },
          error: (e) => {
              console.error('Decoder error:', e);
          }
      });

      const stream = new ReadableStream({
          start(controller) {
              controller.enqueue(new Uint8Array(videoData));
              controller.close();
          }
      });

      const reader = stream.getReader();
        
      while (true) {
            const { done, value } = await reader.read();
            if (done) break;
            decoder.configure({
              codec: 'vp8'
            });
            const encodedChunk = new EncodedVideoChunk({
                type: 'key',
                timestamp: 0,
                byteLength: value.byteLength,
                data: value
            });
            decoder.decode(encodedChunk);
        }

        decoder.close();
  }

  encoder.close();

  const mergedVideoBlob = new Blob(encodedChunks, { type: 'video/webm' });

  return mergedVideoBlob;
}

Upvotes: 0

Views: 51

Answers (0)

Related Questions