[251126] fix: Memory Monitoring - mediaMemory
🕐 커밋 시간: 2025. 11. 26. 09:19:24 📊 변경 통계: • 총 파일: 1개 • 추가: +464줄 • 삭제: -2줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/utils/memoryMonitor.js 🔧 주요 변경 내용: • 공통 유틸리티 함수 최적화 • 대규모 기능 개발
This commit is contained in:
@@ -33,6 +33,253 @@ export const createMemoryMonitor = (enableInitLog = true) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
// 미디어 리소스 메모리 정보 수집
|
||||
const getMediaMemoryInfo = () => {
|
||||
try {
|
||||
const mediaElements = document.querySelectorAll('video, audio');
|
||||
let totalVideoBuffer = 0;
|
||||
let totalAudioBuffer = 0;
|
||||
let videoCount = 0;
|
||||
let audioCount = 0;
|
||||
const mediaInfo = [];
|
||||
|
||||
// NodeList를 배열로 변환하여 forEach 사용
|
||||
Array.from(mediaElements).forEach((media, index) => {
|
||||
try {
|
||||
const buffered = media.buffered;
|
||||
let totalDuration = 0;
|
||||
|
||||
if (buffered && buffered.length) {
|
||||
for (let i = 0; i < buffered.length; i++) {
|
||||
try {
|
||||
totalDuration += buffered.end(i) - buffered.start(i);
|
||||
} catch (e) {
|
||||
// buffered 접근 중 오류 발생 시 무시
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (media.tagName === 'VIDEO') {
|
||||
videoCount++;
|
||||
} else if (media.tagName === 'AUDIO') {
|
||||
audioCount++;
|
||||
}
|
||||
|
||||
// 비디오 메타데이터 수집
|
||||
let videoBitrate = 0;
|
||||
let codecInfo = 'unknown';
|
||||
|
||||
if (media.tagName === 'VIDEO' && media.videoWidth && media.videoHeight) {
|
||||
// 해상도 기반 비트레이트 추정 (HLS 스트리밍 기준)
|
||||
const resolution = media.videoWidth * media.videoHeight;
|
||||
if (resolution >= 3840 * 2160) { // 4K
|
||||
videoBitrate = 15000000; // 15Mbps
|
||||
codecInfo = '4K/HLS';
|
||||
} else if (resolution >= 1920 * 1080) { // FHD
|
||||
videoBitrate = 8000000; // 8Mbps
|
||||
codecInfo = 'FHD/HLS';
|
||||
} else if (resolution >= 1280 * 720) { // HD
|
||||
videoBitrate = 4000000; // 4Mbps
|
||||
codecInfo = 'HD/HLS';
|
||||
} else { // SD
|
||||
videoBitrate = 2000000; // 2Mbps
|
||||
codecInfo = 'SD/HLS';
|
||||
}
|
||||
}
|
||||
|
||||
// HLS 스트리밍 정보 확인
|
||||
let hlsInfo = null;
|
||||
if (media.src && media.src.includes('.m3u8')) {
|
||||
hlsInfo = {
|
||||
isHLS: true,
|
||||
playlistUrl: media.src.substring(0, 100) + '...',
|
||||
estimatedSegments: Math.ceil((media.duration || 0) / 10), // 10초 세그먼트 기준
|
||||
};
|
||||
} else if (media.src) {
|
||||
hlsInfo = {
|
||||
isHLS: false,
|
||||
contentType: 'progressive',
|
||||
format: media.src.includes('.mp4') ? 'MP4' : 'Unknown',
|
||||
};
|
||||
}
|
||||
|
||||
const mediaData = {
|
||||
index,
|
||||
type: media.tagName ? media.tagName.toLowerCase() : 'unknown',
|
||||
src: media.src ? (media.src.length > 50 ? media.src.substring(0, 50) + '...' : media.src) : 'N/A',
|
||||
duration: media.duration || 0,
|
||||
bufferedDuration: totalDuration,
|
||||
currentTime: media.currentTime || 0,
|
||||
readyState: media.readyState || 0,
|
||||
networkState: media.networkState || 0,
|
||||
videoWidth: media.videoWidth || 0,
|
||||
videoHeight: media.videoHeight || 0,
|
||||
// 비디오 전용 정보
|
||||
bitrate: videoBitrate,
|
||||
codecInfo: codecInfo,
|
||||
// HLS/스트리밍 정보
|
||||
hlsInfo: hlsInfo,
|
||||
// 버퍼 효율성
|
||||
bufferEfficiency: media.duration > 0 ? (totalDuration / media.duration * 100).toFixed(1) + '%' : '0%',
|
||||
// 재생 상태
|
||||
paused: media.paused,
|
||||
ended: media.ended,
|
||||
muted: media.muted,
|
||||
volume: media.volume || 0,
|
||||
};
|
||||
|
||||
mediaInfo.push(mediaData);
|
||||
|
||||
// 실제 버퍼 메모리 계산
|
||||
if (media.tagName === 'VIDEO' && media.videoWidth && media.videoHeight) {
|
||||
// 비디오: 실제 비트레이트 기반 계산
|
||||
totalVideoBuffer += totalDuration * (videoBitrate / 8); // bytes
|
||||
} else if (media.tagName === 'AUDIO') {
|
||||
// 오디오: 고품질 320kbps로 추정
|
||||
totalAudioBuffer += totalDuration * 320000 / 8; // bytes
|
||||
}
|
||||
} catch (e) {
|
||||
// 개별 미디어 요소 처리 중 오류 발생 시 무시
|
||||
console.warn('[Memory Monitor] Error processing media element:', e);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
mediaCount: mediaElements.length,
|
||||
videoElements: videoCount,
|
||||
audioElements: audioCount,
|
||||
totalVideoBufferMB: (totalVideoBuffer / 1048576).toFixed(2),
|
||||
totalAudioBufferMB: (totalAudioBuffer / 1048576).toFixed(2),
|
||||
estimatedMediaMemoryMB: ((totalVideoBuffer + totalAudioBuffer) / 1048576).toFixed(2),
|
||||
mediaElements: mediaInfo
|
||||
};
|
||||
} catch (e) {
|
||||
console.warn('[Memory Monitor] Error getting media memory info:', e);
|
||||
return {
|
||||
mediaCount: 0,
|
||||
videoElements: 0,
|
||||
audioElements: 0,
|
||||
totalVideoBufferMB: '0.00',
|
||||
totalAudioBufferMB: '0.00',
|
||||
estimatedMediaMemoryMB: '0.00',
|
||||
mediaElements: []
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 이미지 리소스 메모리 정보 수집
|
||||
const getImageMemoryInfo = () => {
|
||||
try {
|
||||
const images = document.querySelectorAll('img');
|
||||
let totalImageMemory = 0;
|
||||
const imageInfo = [];
|
||||
|
||||
// NodeList를 배열로 변환하여 forEach 사용
|
||||
Array.from(images).forEach((img, index) => {
|
||||
try {
|
||||
if (img.naturalWidth && img.naturalHeight) {
|
||||
// 이미지 메모리 크기 추정 (너비 * 높이 * 4바이트 RGBA)
|
||||
const estimatedMemory = img.naturalWidth * img.naturalHeight * 4;
|
||||
totalImageMemory += estimatedMemory;
|
||||
|
||||
imageInfo.push({
|
||||
index,
|
||||
src: img.src ? (img.src.length > 50 ? img.src.substring(0, 50) + '...' : img.src) : 'N/A',
|
||||
naturalWidth: img.naturalWidth,
|
||||
naturalHeight: img.naturalHeight,
|
||||
displayWidth: img.offsetWidth || 0,
|
||||
displayHeight: img.offsetHeight || 0,
|
||||
estimatedMemoryMB: (estimatedMemory / 1048576).toFixed(2),
|
||||
complete: img.complete || false,
|
||||
loading: img.loading || 'auto'
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// 개별 이미지 요소 처리 중 오류 발생 시 무시
|
||||
console.warn('[Memory Monitor] Error processing image element:', e);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
imageCount: images.length,
|
||||
totalImageMemoryMB: (totalImageMemory / 1048576).toFixed(2),
|
||||
images: imageInfo
|
||||
};
|
||||
} catch (e) {
|
||||
console.warn('[Memory Monitor] Error getting image memory info:', e);
|
||||
return {
|
||||
imageCount: 0,
|
||||
totalImageMemoryMB: '0.00',
|
||||
images: []
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Canvas/WebGL 리소스 메모리 정보 수집
|
||||
const getCanvasMemoryInfo = () => {
|
||||
try {
|
||||
const canvases = document.querySelectorAll('canvas');
|
||||
let totalCanvasMemory = 0;
|
||||
const canvasInfo = [];
|
||||
|
||||
// NodeList를 배열로 변환하여 forEach 사용
|
||||
Array.from(canvases).forEach((canvas, index) => {
|
||||
try {
|
||||
const context = canvas.getContext('2d') || canvas.getContext('webgl') || canvas.getContext('webgl2');
|
||||
if (context) {
|
||||
const memory = canvas.width * canvas.height * 4; // 4바이트 per 픽셀
|
||||
totalCanvasMemory += memory;
|
||||
|
||||
canvasInfo.push({
|
||||
index,
|
||||
width: canvas.width || 0,
|
||||
height: canvas.height || 0,
|
||||
contextType: context.constructor.name || 'unknown',
|
||||
estimatedMemoryMB: (memory / 1048576).toFixed(2)
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// 개별 캔버스 요소 처리 중 오류 발생 시 무시
|
||||
console.warn('[Memory Monitor] Error processing canvas element:', e);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
canvasCount: canvases.length,
|
||||
totalCanvasMemoryMB: (totalCanvasMemory / 1048576).toFixed(2),
|
||||
canvases: canvasInfo
|
||||
};
|
||||
} catch (e) {
|
||||
console.warn('[Memory Monitor] Error getting canvas memory info:', e);
|
||||
return {
|
||||
canvasCount: 0,
|
||||
totalCanvasMemoryMB: '0.00',
|
||||
canvases: []
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 통합 미디어 메모리 정보
|
||||
const getCompleteMediaMemoryInfo = () => {
|
||||
const mediaMemory = getMediaMemoryInfo();
|
||||
const imageMemory = getImageMemoryInfo();
|
||||
const canvasMemory = getCanvasMemoryInfo();
|
||||
|
||||
const totalEstimatedMB = (
|
||||
parseFloat(mediaMemory.estimatedMediaMemoryMB) +
|
||||
parseFloat(imageMemory.totalImageMemoryMB) +
|
||||
parseFloat(canvasMemory.totalCanvasMemoryMB)
|
||||
).toFixed(2);
|
||||
|
||||
return {
|
||||
totalEstimatedMediaMemoryMB: totalEstimatedMB,
|
||||
media: mediaMemory,
|
||||
images: imageMemory,
|
||||
canvas: canvasMemory,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
};
|
||||
|
||||
const getDetailedMemoryInfo = () => {
|
||||
const info = getMemoryInfo();
|
||||
if (!info) return null;
|
||||
@@ -46,6 +293,8 @@ export const createMemoryMonitor = (enableInitLog = true) => {
|
||||
domNodeCount: document.querySelectorAll('*').length,
|
||||
// 리스너 수 (대략값)
|
||||
eventListenerEstimate: Object.keys(window).filter(key => key.startsWith('on')).length,
|
||||
// 미디어 리소스 정보 추가
|
||||
mediaMemory: getCompleteMediaMemoryInfo(),
|
||||
};
|
||||
|
||||
return detailed;
|
||||
@@ -155,7 +404,121 @@ export const createMemoryMonitor = (enableInitLog = true) => {
|
||||
domNodeCount: detailed.domNodeCount,
|
||||
eventListenerEstimate: detailed.eventListenerEstimate,
|
||||
});
|
||||
console.log(`${logMsg} | ${context} | Details: ${detailStr} ${info}`);
|
||||
const mediaMemory = detailed.mediaMemory;
|
||||
const mediaStr = JSON.stringify({
|
||||
totalMediaMemory: mediaMemory.totalEstimatedMediaMemoryMB + 'MB',
|
||||
videoElements: mediaMemory.media.videoElements,
|
||||
audioElements: mediaMemory.media.audioElements,
|
||||
imageCount: mediaMemory.images.imageCount,
|
||||
imageMemory: mediaMemory.images.totalImageMemoryMB + 'MB',
|
||||
canvasCount: mediaMemory.canvas.canvasCount,
|
||||
canvasMemory: mediaMemory.canvas.totalCanvasMemoryMB + 'MB'
|
||||
});
|
||||
|
||||
const jsTotal = parseFloat(detailed.usedJSHeapSize);
|
||||
const mediaTotal = parseFloat(mediaMemory.totalEstimatedMediaMemoryMB);
|
||||
const estimatedTotal = (jsTotal + mediaTotal).toFixed(2);
|
||||
|
||||
console.log(`${logMsg} | ${context} | Details: ${detailStr} | Media: ${mediaStr} | Est.Total: ${estimatedTotal}MB ${info}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 전체 미디어 리소스 메모리 로깅
|
||||
* @param {string} context - 컨텍스트
|
||||
* @param {object} additionalInfo - 추가 정보
|
||||
*/
|
||||
logMediaMemory: (context = '', additionalInfo = {}) => {
|
||||
const jsMem = getMemoryInfo();
|
||||
const mediaMem = getCompleteMediaMemoryInfo();
|
||||
|
||||
if (jsMem && mediaMem) {
|
||||
const jsTotal = parseFloat(jsMem.usedJSHeapSize);
|
||||
const mediaTotal = parseFloat(mediaMem.totalEstimatedMediaMemoryMB);
|
||||
const estimatedTotal = (jsTotal + mediaTotal).toFixed(2);
|
||||
|
||||
const logMsg = formatMemoryLog(jsMem.usedJSHeapSize, jsMem.totalJSHeapSize, jsMem.jsHeapSizeLimit);
|
||||
const info = Object.keys(additionalInfo).length > 0 ? JSON.stringify(additionalInfo) : '';
|
||||
|
||||
console.log(`${logMsg} | Media: ${context}`);
|
||||
console.log(`[Media Breakdown] Images: ${mediaMem.images.totalImageMemoryMB}MB (${mediaMem.images.imageCount}개), Video: ${mediaMem.media.estimatedMediaMemoryMB}MB (${mediaMem.media.mediaCount}개), Canvas: ${mediaMem.canvas.totalCanvasMemoryMB}MB (${mediaMem.canvas.canvasCount}개)`);
|
||||
console.log(`[Total Estimated] JS(${jsTotal}MB) + Media(${mediaTotal}MB) = ${estimatedTotal}MB ${info}`);
|
||||
} else {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[Media Memory] [${timestamp}] ${context} - Browser does not support performance.memory API (추가정보: ${JSON.stringify(additionalInfo)})`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 비디오 전용 상세 메모리 로깅
|
||||
* @param {string} context - 컨텍스트
|
||||
* @param {object} additionalInfo - 추가 정보
|
||||
*/
|
||||
logVideoMemory: (context = '', additionalInfo = {}) => {
|
||||
const jsMem = getMemoryInfo();
|
||||
const mediaMem = getMediaMemoryInfo();
|
||||
|
||||
if (jsMem && mediaMem) {
|
||||
const logMsg = formatMemoryLog(jsMem.usedJSHeapSize, jsMem.totalJSHeapSize, jsMem.jsHeapSizeLimit);
|
||||
const info = Object.keys(additionalInfo).length > 0 ? JSON.stringify(additionalInfo) : '';
|
||||
|
||||
console.log(`${logMsg} | Video Memory: ${context}`);
|
||||
console.log(`[Video Summary] ${mediaMem.videoElements}개 비디오, ${mediaMem.totalVideoBufferMB}MB 버퍼 메모리 사용`);
|
||||
|
||||
// 개별 비디오 정보 상세 출력
|
||||
mediaMem.mediaElements.forEach((video, idx) => {
|
||||
if (video.type === 'video') {
|
||||
console.log(`[Video ${video.index}] ${video.codecInfo} ${video.videoWidth}x${video.videoHeight} | Buffered: ${video.bufferedDuration.toFixed(1)}s/${video.duration.toFixed(1)}s (${video.bufferEfficiency}) | ${video.hlsInfo?.isHLS ? 'HLS' : 'Progressive'} | ${video.paused ? 'Paused' : 'Playing'} | Src: ${video.src}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[Video Estimation] JS Heap: ${jsMem.usedJSHeapSize}MB + Video Buffer: ${mediaMem.totalVideoBufferMB}MB = ${(parseFloat(jsMem.usedJSHeapSize) + parseFloat(mediaMem.totalVideoBufferMB)).toFixed(2)}MB ${info}`);
|
||||
} else {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[Video Memory] [${timestamp}] ${context} - Browser does not support performance.memory API (추가정보: ${JSON.stringify(additionalInfo)})`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* HLS 스트리밍 메모리 전용 로깅
|
||||
* @param {string} context - 컨텍스트
|
||||
* @param {object} additionalInfo - 추가 정보
|
||||
*/
|
||||
logHLSMemory: (context = '', additionalInfo = {}) => {
|
||||
const jsMem = getMemoryInfo();
|
||||
const mediaMem = getMediaMemoryInfo();
|
||||
|
||||
if (jsMem && mediaMem) {
|
||||
const hlsVideos = mediaMem.mediaElements.filter(video => video.hlsInfo && video.hlsInfo.isHLS);
|
||||
const progressiveVideos = mediaMem.mediaElements.filter(video => video.hlsInfo && !video.hlsInfo.isHLS);
|
||||
|
||||
const logMsg = formatMemoryLog(jsMem.usedJSHeapSize, jsMem.totalJSHeapSize, jsMem.jsHeapSizeLimit);
|
||||
const info = Object.keys(additionalInfo).length > 0 ? JSON.stringify(additionalInfo) : '';
|
||||
|
||||
console.log(`${logMsg} | HLS Streaming: ${context}`);
|
||||
console.log(`[Streaming Analysis] HLS: ${hlsVideos.length}개, Progressive: ${progressiveVideos.length}개 | Total Video Memory: ${mediaMem.totalVideoBufferMB}MB`);
|
||||
|
||||
// HLS 비디오 상세 정보
|
||||
if (hlsVideos.length > 0) {
|
||||
console.log(`[HLS Videos]`);
|
||||
hlsVideos.forEach(video => {
|
||||
console.log(` ${video.codecInfo} ${video.videoWidth}x${video.videoHeight} | Segments: ~${video.hlsInfo.estimatedSegments}개 | Buffer: ${video.bufferedDuration.toFixed(1)}s | Efficiency: ${video.bufferEfficiency}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Progressive 비디오 상세 정보
|
||||
if (progressiveVideos.length > 0) {
|
||||
console.log(`[Progressive Videos]`);
|
||||
progressiveVideos.forEach(video => {
|
||||
console.log(` ${video.codecInfo} ${video.videoWidth}x${video.videoHeight} | Format: ${video.hlsInfo.format} | Buffer: ${video.bufferedDuration.toFixed(1)}s`);
|
||||
});
|
||||
}
|
||||
|
||||
const streamingMemoryMB = hlsVideos.reduce((sum, video) => {
|
||||
return sum + parseFloat(video.bufferedDuration) * (video.bitrate / 8 / 1048576);
|
||||
}, 0).toFixed(2);
|
||||
|
||||
console.log(`[Streaming Memory] HLS Buffer: ${streamingMemoryMB}MB | Progressive Buffer: ${(parseFloat(mediaMem.totalVideoBufferMB) - parseFloat(streamingMemoryMB)).toFixed(2)}MB ${info}`);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -165,6 +528,7 @@ export const createMemoryMonitor = (enableInitLog = true) => {
|
||||
*/
|
||||
getMemory: () => getMemoryInfo(),
|
||||
getDetailedMemory: () => getDetailedMemoryInfo(),
|
||||
getMediaMemory: () => getCompleteMediaMemoryInfo(),
|
||||
};
|
||||
|
||||
// 싱글톤 인스턴스 저장
|
||||
@@ -230,11 +594,109 @@ export const createMemoryMonitor = (enableInitLog = true) => {
|
||||
domNodeCount: detailed.domNodeCount,
|
||||
eventListenerEstimate: detailed.eventListenerEstimate,
|
||||
});
|
||||
console.log(`${logMsg} | ${context} | Details: ${detailStr} ${info}`);
|
||||
const mediaMemory = detailed.mediaMemory;
|
||||
const mediaStr = JSON.stringify({
|
||||
totalMediaMemory: mediaMemory.totalEstimatedMediaMemoryMB + 'MB',
|
||||
videoElements: mediaMemory.media.videoElements,
|
||||
audioElements: mediaMemory.media.audioElements,
|
||||
imageCount: mediaMemory.images.imageCount,
|
||||
imageMemory: mediaMemory.images.totalImageMemoryMB + 'MB',
|
||||
canvasCount: mediaMemory.canvas.canvasCount,
|
||||
canvasMemory: mediaMemory.canvas.totalCanvasMemoryMB + 'MB'
|
||||
});
|
||||
|
||||
const jsTotal = parseFloat(detailed.usedJSHeapSize);
|
||||
const mediaTotal = parseFloat(mediaMemory.totalEstimatedMediaMemoryMB);
|
||||
const estimatedTotal = (jsTotal + mediaTotal).toFixed(2);
|
||||
|
||||
console.log(`${logMsg} | ${context} | Details: ${detailStr} | Media: ${mediaStr} | Est.Total: ${estimatedTotal}MB ${info}`);
|
||||
}
|
||||
},
|
||||
|
||||
logMediaMemory: (context = '', additionalInfo = {}) => {
|
||||
const jsMem = getMemoryInfo();
|
||||
const mediaMem = getCompleteMediaMemoryInfo();
|
||||
|
||||
if (jsMem && mediaMem) {
|
||||
const jsTotal = parseFloat(jsMem.usedJSHeapSize);
|
||||
const mediaTotal = parseFloat(mediaMem.totalEstimatedMediaMemoryMB);
|
||||
const estimatedTotal = (jsTotal + mediaTotal).toFixed(2);
|
||||
|
||||
const logMsg = formatMemoryLog(jsMem.usedJSHeapSize, jsMem.totalJSHeapSize, jsMem.jsHeapSizeLimit);
|
||||
const info = Object.keys(additionalInfo).length > 0 ? JSON.stringify(additionalInfo) : '';
|
||||
|
||||
console.log(`${logMsg} | Media: ${context}`);
|
||||
console.log(`[Media Breakdown] Images: ${mediaMem.images.totalImageMemoryMB}MB (${mediaMem.images.imageCount}개), Video: ${mediaMem.media.estimatedMediaMemoryMB}MB (${mediaMem.media.mediaCount}개), Canvas: ${mediaMem.canvas.totalCanvasMemoryMB}MB (${mediaMem.canvas.canvasCount}개)`);
|
||||
console.log(`[Total Estimated] JS(${jsTotal}MB) + Media(${mediaTotal}MB) = ${estimatedTotal}MB ${info}`);
|
||||
} else {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[Media Memory] [${timestamp}] ${context} - Browser does not support performance.memory API (추가정보: ${JSON.stringify(additionalInfo)})`);
|
||||
}
|
||||
},
|
||||
getMemory: () => getMemoryInfo(),
|
||||
getDetailedMemory: () => getDetailedMemoryInfo(),
|
||||
getMediaMemory: () => getCompleteMediaMemoryInfo(),
|
||||
logVideoMemory: (context = '', additionalInfo = {}) => {
|
||||
const jsMem = getMemoryInfo();
|
||||
const mediaMem = getMediaMemoryInfo();
|
||||
|
||||
if (jsMem && mediaMem) {
|
||||
const logMsg = formatMemoryLog(jsMem.usedJSHeapSize, jsMem.totalJSHeapSize, jsMem.jsHeapSizeLimit);
|
||||
const info = Object.keys(additionalInfo).length > 0 ? JSON.stringify(additionalInfo) : '';
|
||||
|
||||
console.log(`${logMsg} | Video Memory: ${context}`);
|
||||
console.log(`[Video Summary] ${mediaMem.videoElements}개 비디오, ${mediaMem.totalVideoBufferMB}MB 버퍼 메모리 사용`);
|
||||
|
||||
// 개별 비디오 정보 상세 출력
|
||||
mediaMem.mediaElements.forEach((video, idx) => {
|
||||
if (video.type === 'video') {
|
||||
console.log(`[Video ${video.index}] ${video.codecInfo} ${video.videoWidth}x${video.videoHeight} | Buffered: ${video.bufferedDuration.toFixed(1)}s/${video.duration.toFixed(1)}s (${video.bufferEfficiency}) | ${video.hlsInfo?.isHLS ? 'HLS' : 'Progressive'} | ${video.paused ? 'Paused' : 'Playing'} | Src: ${video.src}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[Video Estimation] JS Heap: ${jsMem.usedJSHeapSize}MB + Video Buffer: ${mediaMem.totalVideoBufferMB}MB = ${(parseFloat(jsMem.usedJSHeapSize) + parseFloat(mediaMem.totalVideoBufferMB)).toFixed(2)}MB ${info}`);
|
||||
} else {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[Video Memory] [${timestamp}] ${context} - Browser does not support performance.memory API (추가정보: ${JSON.stringify(additionalInfo)})`);
|
||||
}
|
||||
},
|
||||
logHLSMemory: (context = '', additionalInfo = {}) => {
|
||||
const jsMem = getMemoryInfo();
|
||||
const mediaMem = getMediaMemoryInfo();
|
||||
|
||||
if (jsMem && mediaMem) {
|
||||
const hlsVideos = mediaMem.mediaElements.filter(video => video.hlsInfo && video.hlsInfo.isHLS);
|
||||
const progressiveVideos = mediaMem.mediaElements.filter(video => video.hlsInfo && !video.hlsInfo.isHLS);
|
||||
|
||||
const logMsg = formatMemoryLog(jsMem.usedJSHeapSize, jsMem.totalJSHeapSize, jsMem.jsHeapSizeLimit);
|
||||
const info = Object.keys(additionalInfo).length > 0 ? JSON.stringify(additionalInfo) : '';
|
||||
|
||||
console.log(`${logMsg} | HLS Streaming: ${context}`);
|
||||
console.log(`[Streaming Analysis] HLS: ${hlsVideos.length}개, Progressive: ${progressiveVideos.length}개 | Total Video Memory: ${mediaMem.totalVideoBufferMB}MB`);
|
||||
|
||||
// HLS 비디오 상세 정보
|
||||
if (hlsVideos.length > 0) {
|
||||
console.log(`[HLS Videos]`);
|
||||
hlsVideos.forEach(video => {
|
||||
console.log(` ${video.codecInfo} ${video.videoWidth}x${video.videoHeight} | Segments: ~${video.hlsInfo.estimatedSegments}개 | Buffer: ${video.bufferedDuration.toFixed(1)}s | Efficiency: ${video.bufferEfficiency}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Progressive 비디오 상세 정보
|
||||
if (progressiveVideos.length > 0) {
|
||||
console.log(`[Progressive Videos]`);
|
||||
progressiveVideos.forEach(video => {
|
||||
console.log(` ${video.codecInfo} ${video.videoWidth}x${video.videoHeight} | Format: ${video.hlsInfo.format} | Buffer: ${video.bufferedDuration.toFixed(1)}s`);
|
||||
});
|
||||
}
|
||||
|
||||
const streamingMemoryMB = hlsVideos.reduce((sum, video) => {
|
||||
return sum + parseFloat(video.bufferedDuration) * (video.bitrate / 8 / 1048576);
|
||||
}, 0).toFixed(2);
|
||||
|
||||
console.log(`[Streaming Memory] HLS Buffer: ${streamingMemoryMB}MB | Progressive Buffer: ${(parseFloat(mediaMem.totalVideoBufferMB) - parseFloat(streamingMemoryMB)).toFixed(2)}MB ${info}`);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return memoryMonitorInstance;
|
||||
|
||||
Reference in New Issue
Block a user