만들리에/CropMon (스크린레코더)

크롭몬 버그픽스(v1.0.1) - 윈도우에서 레코딩 화질 깨지는 이슈

gamz 2023. 7. 24. 01:02

문제

크롭몬(v1.0.0)으로 윈도우 환경에서 레코딩시 가끔씩 아래 영상처럼 색상이 잘못 표현되는 문제가 있었다. (수평 라인들이 보이며 뭔가 패턴이 있는 것 같다)

 

삽질

일단 재현 경로만 확실히 알면 원인과 솔루션을 찾는건 쉽다. 하지만 이건 맥에서는 전혀 재현이 안되고 윈도우에서도 잘될때는 계속되고 안될때는 계속 안되는 등 도무지 패턴을 못 찾겠는거다. 이런저런 시도들을 해봤는데 효과가 없었다. (별로 의미 없음 무시)

  • 두 영상 소스를 머지하는 부분을 Worker 에서 Renderer 프로세스로 다시 가져와보기
  • 캔버스를 두개를 활용해서 일종의 더블버퍼링을 해보기 
  • 프레임레이트를 낮춰서 캔버스 Draw 빈도를 줄이기

 

아이디어

그렇게 주말이 지나가고 있었다. 빨리 정리하고 당분간 좀 쉬고 싶었다. 하지만 이 하찮은(?) 문제가 나를 놓아주지 않는다. FFmpeg 리서치할때의 악몽이 떠오르려는 순간, 인코더에 프레임을 넣을때는 인코더가 요구하는 스펙대로(포맷, 사이즈 등) 맞춰줘야한다는게 함께 떠올랐다. 역시 노력은 배신하지 않는다. 이렇게 연결될 줄이야.

 

그래서 혹시나 캔버스의 사이즈(MediaRecorder로 넘어가는 스트림)에 영향을 받나 싶어 해상도를 홀수/짝수 다양하게 해봤더니 너비가 홀수일때만 이미지가 깨진다는걸 발견했다. 재현을 했으니 수정은 쉽다.

 

솔루션

캔바스 사이즈를 할당해주는 부분에서 홀수가 나오지 않도록 보정하여 사용했다.

function createCanvasStream = (drawContext: DrawContext): MediaStream => {
  const { canvasBounds } = drawContext;

  const canvas = document.createElement('canvas');
  
  // 기존코드 - 주어진대로 사용하고 있었는데 이 너비가 홀수면,
  // MediaRecorder에서 이를 인코딩할때 문제가 생김 (Windows에서만)
  // canvas.width = canvasBounds.width;
  // canvas.height = canvasBounds.height;

  // 수정 - 그래서 캔바스 사이즈를 잡을때 홀수 값이 나오지 않도록 보정(align) 값을 사용
  const alignedCanvasBounds = alignedBounds(canvasBounds);
  canvas.width = alignedCanvasBounds.width;
  canvas.height = alignedCanvasBounds.height;

  const canvasCtx = canvas.getContext('2d');
  const canvasStream = canvas.captureStream(drawContext.frameRate);

  const videos = drawContext.drawables.map(({ videoStream }) => {
    const video = document.createElement('video');
    video.srcObject = videoStream;
    video.play();
    return video;
  });

  function drawVideosOnCanvas() {
    videos.forEach((video, i) => {
      const { srcBounds, dstBounds } = drawContext.drawables[i];

      canvasCtx?.drawImage(
        video,
        srcBounds.x,
        srcBounds.y,
        srcBounds.width,
        srcBounds.height,
        dstBounds.x,
        dstBounds.y,
        dstBounds.width,
        dstBounds.height,
      );
    });

    requestAnimationFrame(drawVideosOnCanvas);
  }

  drawVideosOnCanvas();

  return canvasStream;
};

function startRecord() {
  ...

  const canvasStream = createCanvasStream(drawContext);
  const mediaRecorder = new MediaRecorder(stream, recOpts);
  ...

  mediaRecorder.start();
 
  ...
}

그랬더니 더이상 해상도에 따라 발생하던 문제가 발생하지 않는다.

원인은 아마도 추측컨데, 인코딩시에 사용하는 하드웨어코덱(혹은 소프트웨어 코덱이라도)이 맥과 윈도우간에 달라서 그런게 아닌가 싶다.