Playwright + OpenCV를 이용해서 비디오 레코딩을 해봅시다.
Playwright는 스크린샷을 찍어서 바이트 어레이로 받을 수 있기 때문에 다음과 같이 하면 된다.
fun record(browser: Browser, width: Int, height: Int, url: String, fps: Int, length: Int) {
val frames = fps * length
val context = browser.newContext(
Browser.NewContextOptions()
.setScreenSize(width, height)
.setViewportSize(width, height)
)
val page = context.newPage()
page.navigate(url, Page.NavigationOptions()
.setTimeout(300000.0)
.setWaitUntil(WaitUtilState.NETWORKIDLE))
val writer = VideoWriter("test.mov",
VideoWriter.fourcc('a', 'v', 'c', '1'),
fps.toDouble(),j Size(width.toDouble(), height.toDouble()
)
for (frame in 0 until frames) {
val bytes = page.screenshot(Page.ScreenshotOptions()
.setType(ScreenshotType.PNG)
.setScale(ScreenshotType.DEVICE)
)
val mat = Imgcodecs.imdecode(MatOfByte(*bytes), CvType.CV_32S)
writer.write(mat)
}
writer.release()
}
물론 스크린샷 찍는데 100ms정도 걸리므로 fps는 있으나마나다.
끗
아무리 생각해도 위 방법은 별로다.
완성품이 별로다.
Playwright는 페이지가 실행되고 나서부터의 행적을 녹화할 수 있는데, 이걸 이용하는게 훨씬 좋을 것 같다.
물론 처음 페이지가 로딩되는 것까지 녹화가 되므로 이 부분은 잘라내야한다. 어떻게? 잘.
fun recordPage(filePath: String, url: String, width: Int, height: Int, length: Long) {
playwright {
executablePath("path/to/chrome/executable")
launch { browser ->
val context = browser.newContext(
Browser.NewContextOptions()
.setScreenSize(width, height)
.setViewportSize(width, height)
.setRecordVideoDir(Path("temp/videos")
.setRecordVideoSize(width, height)
)
val start = System.currentTimeMillis()
val page = context.newPage()
page.navigate(
url,
Page.NavigationOptions()
.setWaitUntil(WaitUntilState.NETWORKIDLE)
)
val end = System.currentTimeMillis()
val loadingTime = (end - start) / 1000
// 여유 있게 5초 정도 더 찍음
TimeUnit.SECOND.sleep(loadingTime + length + 5)
page.close()
val video = page.video()
val capture = VideoCapture(video!!.path().absolutePathString())
val frameRate = capture.get(Videoio.CAP_PROP_FPS)
val targetFramesLength = (frameRate * length).toInt()
// 여유 있게 2초 정도 더 줌
val loadingFrame = (frameRate * (loadingTime + 2)).toInt()
val writer = VideoWriter(filePath, VideoWriter.fourcc('a', 'v', 'c', '1'), frameRate, Size(width.toDouble(), height.toDouble()))
for (f in 0 until loadingFrame + targetFramesLength) {
val frame = Mat()
capture.read(frame)
if (f < loadingFrame)
continue
if (frame.empty())
break
writer.write(frame)
}
writer.release()
}
}
}
영상 커서 옮기는게 VideoCapture.set 으로 된다는데 잘 안되서 어거지로 처음부터 읽되 로딩중이었던 프레임은 무시하는 것으로 했다.
끗