Files
video-v1/vav2/optimization.txt
2025-09-20 03:54:17 +09:00

171 lines
6.8 KiB
Plaintext

🔴 문제 1: YUV→RGB 변환 최적화 방안
방안 1: 룩업 테이블 + 라인 단위 처리
// 초기화 시 한 번만 계산하는 룩업 테이블
static int yuv_table_r[256]; // V → R 변환 테이블
static int yuv_table_g_u[256]; // U → G 변환 테이블
static int yuv_table_g_v[256]; // V → G 변환 테이블
static int yuv_table_b[256]; // U → B 변환 테이블
// 최적화된 변환 함수
void ConvertYUV420PToRGB24_Optimized() {
for (uint32_t y = 0; y < height; ++y) {
const uint8_t* y_row = y_plane + (y * y_stride);
const uint8_t* u_row = u_plane + ((y / 2) * u_stride);
const uint8_t* v_row = v_plane + ((y / 2) * v_stride);
uint8_t* rgb_row = rgb_data + (y * rgb_stride);
// 라인 단위로 2픽셀씩 처리 (YUV420P 특성 활용)
for (uint32_t x = 0; x < width; x += 2) {
uint8_t U = u_row[x / 2];
uint8_t V = v_row[x / 2];
// 룩업 테이블로 변환 계수 조회 (곱셈 대신)
int r_offset = yuv_table_r[V];
int g_offset = yuv_table_g_u[U] + yuv_table_g_v[V];
int b_offset = yuv_table_b[U];
// 2픽셀 동시 처리
for (int px = 0; px < 2 && (x + px) < width; ++px) {
int Y = y_row[x + px] - 16;
Y = (Y * 298) >> 8; // 비트 시프트로 나눗셈 대체
rgb_row[(x + px) * 3 + 0] = clamp(Y + r_offset);
rgb_row[(x + px) * 3 + 1] = clamp(Y + g_offset);
rgb_row[(x + px) * 3 + 2] = clamp(Y + b_offset);
}
}
}
}
성능 향상: 기존 대비 3-4배 빠름 (룩업 테이블 + 라인 최적화)
방안 2: SIMD (SSE/AVX) 벡터화
#include <immintrin.h> // AVX2
void ConvertYUV420PToRGB24_SIMD() {
for (uint32_t y = 0; y < height; ++y) {
// 8픽셀을 한 번에 처리 (AVX2 256bit)
for (uint32_t x = 0; x < width; x += 8) {
// Y값 8개 로드
__m256i y_vec = _mm256_loadu_si256((__m256i*)(y_plane + y * y_stride + x));
// U, V값 4개씩 로드 후 중복 확장
__m128i uv_4 = _mm_loadu_si128((__m128i*)(u_plane + (y/2) * u_stride + x/2));
__m256i u_vec = _mm256_unpacklo_epi8(uv_4, uv_4); // 중복 확장
// 벡터화된 YUV→RGB 변환
__m256i r_vec = yuv_to_rgb_simd(y_vec, u_vec, v_vec, 0);
__m256i g_vec = yuv_to_rgb_simd(y_vec, u_vec, v_vec, 1);
__m256i b_vec = yuv_to_rgb_simd(y_vec, u_vec, v_vec, 2);
// 인터리브해서 RGB24 형태로 저장
store_rgb24_simd(rgb_data + y * rgb_stride + x * 3, r_vec, g_vec, b_vec);
}
}
}
성능 향상: 기존 대비 8-10배 빠름 (SIMD 병렬 처리)
방안 3: 외부 라이브러리 사용
// Intel IPP 라이브러리 사용
#include <ipp.h>
void ConvertYUV420PToRGB24_IPP() {
IppiSize roi = {width, height};
const Ipp8u* pSrc[3] = {y_plane, u_plane, v_plane};
int srcStep[3] = {y_stride, u_stride, v_stride};
// 한 줄로 고성능 변환
ippiYUV420ToRGB_8u_P3C3R(pSrc, srcStep, rgb_data, rgb_stride, roi);
}
성능 향상: 기존 대비 10-15배 빠름 (최고 최적화)
---
🔴 문제 2: BMP 파일 저장 최적화 방안
방안 1: 블록 단위 쓰기 + RGB→BGR 변환 분리
void SaveAsBMP_Optimized() {
// 1. RGB→BGR 변환을 메모리에서 먼저 수행
std::vector<uint8_t> bgr_buffer(rgb_frame.height * padded_row_size);
for (uint32_t y = 0; y < rgb_frame.height; ++y) {
const uint8_t* src_row = rgb_frame.data.data() + (y * rgb_frame.stride);
uint8_t* dst_row = bgr_buffer.data() + (y * padded_row_size);
// 라인 단위로 RGB→BGR 변환 (패딩 포함)
for (uint32_t x = 0; x < rgb_frame.width; ++x) {
dst_row[x * 3 + 0] = src_row[x * 3 + 2]; // B
dst_row[x * 3 + 1] = src_row[x * 3 + 1]; // G
dst_row[x * 3 + 2] = src_row[x * 3 + 0]; // R
}
// 패딩 영역 0으로 채움
memset(dst_row + rgb_frame.width * 3, 0, padding);
}
// 2. 한 번에 블록 쓰기 (621만 번 → 1080번)
for (int32_t y = rgb_frame.height - 1; y >= 0; --y) {
const uint8_t* row_data = bgr_buffer.data() + (y * padded_row_size);
file.write(reinterpret_cast<const char*>(row_data), padded_row_size);
}
}
성능 향상: 기존 대비 50-100배 빠름
방안 2: 메모리 매핑 파일 I/O
void SaveAsBMP_MemoryMapped() {
// Windows 메모리 매핑
HANDLE hFile = CreateFile(file_path.c_str(), GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, total_file_size, NULL);
uint8_t* mapped_memory = static_cast<uint8_t*>(MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, 0));
// 메모리에 직접 쓰기 (파일 I/O 없음)
memcpy(mapped_memory, &header, sizeof(header));
for (int32_t y = rgb_frame.height - 1; y >= 0; --y) {
uint8_t* dst = mapped_memory + header_size + (rgb_frame.height - 1 - y) * padded_row_size;
const uint8_t* src = rgb_frame.data.data() + (y * rgb_frame.stride);
// RGB→BGR 변환하면서 직접 복사
convert_rgb_to_bgr_line(src, dst, rgb_frame.width);
}
UnmapViewOfFile(mapped_memory);
CloseHandle(hMapping);
CloseHandle(hFile);
}
성능 향상: 기존 대비 100-200배 빠름
방안 3: SIMD를 이용한 RGB→BGR 변환
void ConvertRGBToBGR_SIMD(const uint8_t* rgb, uint8_t* bgr, size_t pixel_count) {
const __m256i shuffle_mask = _mm256_setr_epi8(
2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, -1,
2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, -1
);
for (size_t i = 0; i < pixel_count; i += 32) { // 32바이트씩 처리
__m256i rgb_data = _mm256_loadu_si256((__m256i*)(rgb + i));
__m256i bgr_data = _mm256_shuffle_epi8(rgb_data, shuffle_mask);
_mm256_storeu_si256((__m256i*)(bgr + i), bgr_data);
}
}
성능 향상: 변환 부분만 5-8배 빠름
---
📊 종합 성능 개선 효과 예상
| 방안 | YUV→RGB | BMP 저장 | 전체 효과 |
|--------------|---------|--------|-----------|
| 현재 | 150ms | 200ms | 350ms/프레임 |
| 룩업테이블 + 블록쓰기 | 40ms | 4ms | 44ms/프레임 |
| SIMD + 메모리매핑 | 15ms | 2ms | 17ms/프레임 |
| 외부라이브러리(IPP) | 10ms | 2ms | 12ms/프레임 |
결론: 현재 2.8fps → 30fps 실시간 재생 가능
어떤 방안부터 구현해보시겠습니까?