C# - 화면 캡처한 이미지를 ffmpeg(FFmpeg.AutoGen)로 동영상 처리
지난 글에서는,
C# - snagit처럼 화면 캡처를 연속으로 수행해 동영상 제작
; https://www.sysnet.pe.kr/2/0/12895
동영상 처리를 OpenCvSharp.VideoWriter를 이용해 처리했는데요, 그 부분만 ffmpeg로 바꿔볼까요? ^^
자, 그럼 일단
지난 예제 코드 파일의 프로젝트를 로드하고 FFmpeg.AutoGen 패키지를 참조 추가한 후,
// Install-Package FFmpeg.AutoGen -Version 4.4.1.1
Install-Package FFmpeg.AutoGen
네이티브 DLL을 "FFmpeg" 디렉터리를 만들어 /bin/x64 디렉터리에 복사한 후 "Copy if newer" 빌드 설정을 합니다. 그다음, ffmpeg.RootPath를 /FFmpeg/bin/x64로 설정하면 이제 다음의 코드를 넣어 잘 동작할 수 있는 환경이 완료됩니다.
public Form1()
{
// ...[생략]...
FFmpegBinariesHelper.RegisterFFmpegBinaries();
}
이제부터는, 실제적인 ffmpeg 관련 코딩을 해야 하는데요,
바닥부터 하기보다는 FFmpeg.AutoGen의 예제에서 제공하던
H264VideoStreamEncoder.cs 파일을 그대로 복사해, 기존의 VideoWriter를 사용했던 코드를 최대한 그대로 재사용하기 위해 FFmpegVideoWriter를 만들어 H264VideoStreamEncoder에 연결하는 코드를 다음과 같이 작성했습니다.
public class FFmpegVideoWriter : IDisposable
{
double _fps;
public double Fps => _fps;
OpenCvSharp.Size _frameSize;
public OpenCvSharp.Size FrameSize => _frameSize;
FileStream _outputStream;
H264VideoStreamEncoder _streamEncoder;
VideoFrameConverter _vfc;
int _frameNumber = 0;
public FFmpegVideoWriter(string filePath, FourCC type, double fps,
OpenCvSharp.Size frameSize, bool color)
{
_frameSize = frameSize;
_fps = fps;
System.Drawing.Size imageSize = new System.Drawing.Size(frameSize.Width, frameSize.Height);
AVPixelFormat sourcePixelFormat = AVPixelFormat.AV_PIX_FMT_BGR24;
AVPixelFormat destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_YUV420P;
_outputStream = File.Open(filePath, FileMode.Create);
_streamEncoder = new H264VideoStreamEncoder(_outputStream, AVCodecID.AV_CODEC_ID_H264, destinationPixelFormat, (int)fps, imageSize);
_vfc = new VideoFrameConverter(imageSize, sourcePixelFormat, imageSize, destinationPixelFormat);
}
public unsafe void Write(Mat matFrame)
{
// ...[생략]...
}
public void Dispose()
{
_streamEncoder.Dispose();
_outputStream.Dispose();
_vfc.Dispose();
}
}
이렇게 바꾸고 실행했더니, 일단 동작은 잘 하는데
AV_PIX_FMT_BGR24 포맷에서 AV_PIX_FMT_YUV420P 포맷으로 바뀌는 과정에 꽤나 데이터 손실이 발생해 이미지가 많이 뭉개집니다. (대신, 출력 파일의 크기는 예전에 비해 확실히 용량이 작아집니다.)
(2022-02-11 업데이트:
bit_rate의 값을 높였더니 이미지가 뭉개지는 현상은 없어졌습니다.)
그나저나, ffmpeg에 대해 거의 모르니 저 데이터 손실을 없앨 방법을 모르겠군요. ^^; "AVPixelFormat destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_YUV420P"의 값을 AV_PIX_FMT_YUYV422로 바꿨더니 "ffmpeg.avcodec_open2(_pCodecContext, _pCodec, null).ThrowExceptionIfError();" 호출에서 "System.ApplicationException: 'Invalid argument'" 오류가 발생합니다.
H264 코덱이 좀 더 해상도가 높은 인코딩 방식을 지원하지 않는다는 것은 말이 안 되는 듯한데... 아마도 제가 모르는 다른 인자가 있겠지요. ^^ (혹시 이에 대해서 아시는 분은 덧글 부탁드립니다.)
암튼, 기초는 끝냈으니... 조금씩 예제 코드를 확장해 보겠습니다. ^^
(
첨부 파일은 이 글의 예제 코드를 포함합니다. 단지, 압축 파일 크기를 줄이기 위해 ./FFmpeg/bin/x64 하위의 DLL은 제거했습니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]