-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
2,149 additions
and
192 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import React, { useEffect, useRef } from "react"; | ||
|
||
const RealTimeVideoPage = () => { | ||
const videoRef = useRef<HTMLVideoElement>(null); | ||
const canvasRef = useRef<HTMLCanvasElement>(null); | ||
|
||
// 비디오 스트림 가져오기 | ||
const startStreaming = async () => { | ||
try { | ||
const constraints = { video: true }; | ||
const stream = await navigator.mediaDevices.getUserMedia(constraints); | ||
if (videoRef.current) { | ||
videoRef.current.srcObject = stream; | ||
} | ||
} catch (error) { | ||
console.error("비디오 스트림 가져오기 오류:", error); | ||
} | ||
}; | ||
|
||
// Canvas를 사용해 비디오 프레임을 JPEG로 캡처하고 서버에 전송 | ||
const captureAndSendFrame = async () => { | ||
if (canvasRef.current && videoRef.current) { | ||
const canvas = canvasRef.current; | ||
const video = videoRef.current; | ||
|
||
// Canvas 크기를 비디오와 동일하게 설정 | ||
canvas.width = video.videoWidth; | ||
canvas.height = video.videoHeight; | ||
|
||
// Canvas에 현재 비디오 프레임 그리기 | ||
const context = canvas.getContext("2d"); | ||
if (context) { | ||
context.drawImage(video, 0, 0, canvas.width, canvas.height); | ||
|
||
// 캡처된 Canvas를 JPEG Blob으로 변환 | ||
canvas.toBlob(async (blob) => { | ||
if (blob) { | ||
// JPEG 이미지를 서버로 전송 | ||
await sendImageToServer(blob); | ||
} | ||
}, "image/jpeg"); | ||
} | ||
} | ||
}; | ||
|
||
// Blob 데이터를 서버에 전송하는 함수 | ||
const sendImageToServer = async (blob: Blob) => { | ||
const formData = new FormData(); | ||
formData.append("image", blob, "frame.jpg"); | ||
|
||
try { | ||
const response = await fetch("/api/upload-image", { | ||
method: "POST", | ||
body: formData, | ||
}); | ||
if (!response.ok) { | ||
throw new Error("이미지 전송 오류"); | ||
} | ||
console.log("이미지 전송 성공"); | ||
} catch (error) { | ||
console.error("이미지 전송 실패:", error); | ||
} | ||
}; | ||
|
||
// 비디오 스트리밍 시작 및 일정 간격으로 프레임 캡처 | ||
useEffect(() => { | ||
startStreaming(); | ||
|
||
// 0.1초에 한 번씩 프레임 캡처 및 전송 | ||
const captureInterval = setInterval(captureAndSendFrame, 100); | ||
return () => clearInterval(captureInterval); | ||
}, []); | ||
|
||
return ( | ||
<div> | ||
<h1>실시간 JPEG 이미지 전송</h1> | ||
<video ref={videoRef} autoPlay playsInline style={{ display: "none" }} /> | ||
<canvas ref={canvasRef} style={{ display: "none" }} /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default RealTimeVideoPage; |
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const HomeCta = () => { | ||
return ( | ||
<div className="mx-[8vw] flex flex-col items-center gap-4"> | ||
<button className="w-full py-4 rounded-[10px] bg-[rgba(237,237,237,0.8)] text-[#0e1d3c] text-[18px]]"> | ||
시험장 접속 | ||
</button> | ||
<button className="bg-none border-b border-white text-[#d9d9d9] text-[10px]"> | ||
이용에 불편함이 있으신가요? | ||
</button> | ||
</div> | ||
); | ||
}; | ||
|
||
export default HomeCta; |
12 changes: 12 additions & 0 deletions
12
src/frontend/eyesee-user/src/components/home/HomeHeader.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import LogoIcon from "@/assets/icons/Logo.svg"; | ||
|
||
const HomeHeader = () => { | ||
return ( | ||
<div className="px-[6vw] py-[4vh] flex justify-between items-center"> | ||
<LogoIcon /> | ||
<div className="text-[18px] text-white cursor-pointer">About us</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default HomeHeader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters