windows c++에서 rawvideo를 ffmpeg.exe를 이용 pipe로 압축하기 질문입니다.
페이지 정보
본문
다음과 같이 bgr24로 된 rawvideo를 ffmpeg.exe에 파이프 출력하여 압축을 진행했습니다.
//==============================================================
const char* ffmpeg_write_cmd = "ffmpeg -y -f rawvideo -pix_fmt bgr24 -s 1280x720 -r 24 -i - -c:v libx264 -b:v 3000k output.mp4";
FILE *fp_write;
fp_write = _popen(cmd_write, "wb");
if(!fp_write)
return -1;
// 비디오 프레임의 크기 설정
int width = 1280;
int height = 720;
int frame_size = width * height * 3; // BGR 포맷 (3채널)
cv::Mat frame(height, width, CV_8UC3);
std::vector<uchar> buffer(frame_size);
while (true) {
//
//buffer는 어디에선가 가져욤
// 버퍼를 OpenCV Mat 객체로 복사
std::memcpy(frame.data, buffer.data(), frame_size);
// 프레임을 화면에 표시
cv::imshow("Frame", frame);
if (cv::waitKey(10) == 'q') {
break;
}
// 프레임 데이터를 FFmpeg로 쓰기
fwrite(buffer.data(), 1, size_write, fp_write);
}
_pclose(fp_write);
cv::destroyAllWindows();
return 0;
//==================================================================
그런데 _popen을 이용하면 ffmpeg.exe 실행될 때 콘솔창이 나오기 때문에 콘솔창을 없애려고 알아보니
CreatePipe와 CreateProcess를 이용해야 한다고 하더군요. 그래서 이리저리 삽질끝에 아래와 같이 수정하였습니다.
//-------------------------------------------------------------------------------------------------
const char* ffmpeg_write_cmd = "ffmpeg -y -f rawvideo -pix_fmt bgr24 -s 1280x720 -r 24 -i - -c:v libx264 -b:v 3000k output.mp4";
// 파이프 생성 (FFmpeg로 비디오 데이터 쓰기)
HANDLE hWritePipeRead, hWritePipeWrite;
if (!CreatePipe(&hWritePipeRead, &hWritePipeWrite, &sa, 0)) {
std::cerr << "Error: Could not create write pipe." << std::endl;
return -1;
}
// FFmpeg 쓰기 프로세스 설정
STARTUPINFO si_write = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi_write;
si_write.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si_write.wShowWindow = SW_HIDE; // 콘솔 창 숨기기
si_write.hStdInput = hWritePipeRead;
// FFmpeg 쓰기 프로세스 시작
if (!CreateProcess(NULL, (LPSTR)ffmpeg_write_cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si_write, &pi_write)) {
std::cerr << "Error: Could not start FFmpeg write process." << std::endl;
CloseHandle(hWritePipeRead);
CloseHandle(hWritePipeWrite);
return -1;
}
// 쓰기 파이프 읽기 핸들 닫기 (쓰기 파이프만 사용)
CloseHandle(hWritePipeRead);
// 비디오 프레임의 크기 설정
int width = 1280;
int height = 720;
int frame_size = width * height * 3; // BGR 포맷 (3채널)
cv::Mat frame(height, width, CV_8UC3);
std::vector<uchar> buffer(frame_size);
while (true) {
//
//buffer는 어디에선가 가져욤
// 버퍼를 OpenCV Mat 객체로 복사
std::memcpy(frame.data, buffer.data(), frame_size);
// 프레임을 화면에 표시
cv::imshow("Frame", frame);
if (cv::waitKey(10) == 'q') {
break;
}
// 프레임 데이터를 FFmpeg로 쓰기
DWORD bytesWritten;
if (!WriteFile(hWritePipeWrite, buffer.data(), frame_size, &bytesWritten, NULL) || bytesWritten != frame_size) {
std::cerr << "Error: Could not write frame to pipe." << std::endl;
break;
}
FlushFileBuffers(hWritePipeWrite);
}
// 파이프 및 프로세스 핸들 닫기
CloseHandle(hWritePipeWrite); // close를 하면 ffmpeg이 종료되어야 하는데 종료되지 않음
// FFmpeg 쓰기 프로세스 종료
//TerminateProcess(pi_write.hProcess, 0);
WaitForSingleObject(pi_write.hProcess, INFINITE); // 강제로 종료하지 않으면 무한대기, 강제 종료하면 output.mp4가 정상종료되지 않아 플레이어에서 읽을 수 없음
CloseHandle(pi_write.hProcess);
CloseHandle(pi_write.hThread);
cv::destroyAllWindows();
return 0;
//-----------------------------------------------------------------------------------------
문제는 위 코드의 코멘트와 같이 CloseHandle을 하면 ffmpeg이 쓰기를 종료해야 하는데 그렇지 않고 프로세스가 계속 살아있어서 저장이 완료가 되지 않습니다.
그렇다고 강제로 종료시켜도 마찮가지로 저장이 완료가 되지 않구요
_popen, _pclose를 사용하면 결과가 잘 인코딩되어서 저장됩니다.
문제가 뭘까요?
- 게시물이 없습니다.
BLUEnLIVE님의 댓글
필터 권한 문제니 뭐니 하는 글들 많아서 다 해봤지만 제 결론은 그냥 파일의 끝을 찾는 건 불가능하다는 것이었습니다.
TCP 소켓을 만들어 내부적으로 전송하는 테크닉이 있긴 합니다.
ffmpeg 끼리 할 때는 TCP 소켓으로 전송하니 이건 잘 인식이 됐었습니다.