Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)
(시리즈 글이 10개 있습니다.)
VC++: 121. DXGI를 이용한 윈도우 화면 캡처 소스 코드(Visual C++)
; https://www.sysnet.pe.kr/2/0/11385

.NET Framework: 705. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드
; https://www.sysnet.pe.kr/2/0/11400

.NET Framework: 706. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드 + Direct2D 출력
; https://www.sysnet.pe.kr/2/0/11401

.NET Framework: 712. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드 + Direct2D 출력 + OpenCV
; https://www.sysnet.pe.kr/2/0/11407

.NET Framework: 713. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드 + Direct2D 출력 + OpenCV (2)
; https://www.sysnet.pe.kr/2/0/11408

.NET Framework: 913. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 라이브러리
; https://www.sysnet.pe.kr/2/0/12238

.NET Framework: 1123. C# - (SharpDX + DXGI) 화면 캡처한 이미지를 빠르게 JPG로 변환하는 방법
; https://www.sysnet.pe.kr/2/0/12889

.NET Framework: 1126. C# - snagit처럼 화면 캡처를 연속으로 수행해 동영상 제작
; https://www.sysnet.pe.kr/2/0/12895

.NET Framework: 1128. C# - 화면 캡처한 이미지를 ffmpeg(FFmpeg.AutoGen)로 동영상 처리
; https://www.sysnet.pe.kr/2/0/12897

.NET Framework: 1152. C# - 화면 캡처한 이미지를 ffmpeg(FFmpeg.AutoGen)로 동영상 처리 (저해상도 현상 해결)
; https://www.sysnet.pe.kr/2/0/12963




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은 제거했습니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 2/11/2022]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2022-01-03 10시54분
[이승준] AV_PIX_FMT_YUYV422 이것의 변경에서 에러가 나는것은 두가지 경우를 생각해 볼 수 있습니다.

1. 인코더가 해당 컬러포맷을 지원하지 않는 경우.
2. 컬러포맷 컨버터를 지원하지 않도록 만든 경우.

1번의 경우는 인코더마다 지원하는 컬러포맷이 다릅니다.
문제는 위의 코드로는 어떤 코덱이 선택되었는지 조차도 알수가 없고,
에러처리를 코덱 선택 부분에서 실제 지원 컬러포맷을 확인해서 처리했는지?
아니면 그냥 범용적으로 사용되는 컬러포맷이 아닐 경우 전부 오류 처리를 했는지 알수가 없다는거죠.

2번의 경우는 가능성이 거의 없습니다.
ffmpeg 포맷 컨버터는 특수한 컬러포맷이 아니면 거의 변환을 합니다.
당연히 YUYV422은 문제가 없죠.
[guest]
2022-01-03 11시03분
@이승준 덧글 감사합니다. 1번의 경우를 언급하면서 본문의 코드에서 어떤 코덱이 선택되었는지 알 수가 없다고 했는데, 그렇다면 "AVCodecID.AV_CODEC_ID_H264"라는 식별자도 H264를 지원하는 것들의 다양한 코덱 종류에 대한 대표값에 불과하다는 거죠?
정성태
2022-01-03 12시54분
[이승준] 정성태님 맞습니다.
다만 보통 기본 인코더가 선택이 되는데. 이게 라이브러리 빌드에 따라서 달라집니다.
ffmpeg.org에서 다운로드 받는것 중 gpl3기준일 경우 libx264가 올라오고요.
lgpl일 경우 아주 기본적인 소프트웨어 인코더가 올라오거나 아니면 gpu에 따라 gpu인코더가 올라오기도 합니다.
vcpkg 로 직접 빌드할 경우에는 딱 기본적인 라이브러리만 추가되서 빌드될겁니다.

https://github.com/m-ab-s/media-autobuild_suite
요건 윈도우즈에서 최신버전의 ffmpeg을 본인 입맛대로 빌드할 수 있는 스크립트가 제공되는 깃허브 입니다.
단점은 간헐적으로 버그가 발생하면 빌드가 안되는 경우도 있습니다. 그리고 ffmpeg을 그때그때 다운로드 받기 때문에 소스 수정은 불가능 합니다.
스크립트 자체를 수정하면 물론 가능하고요.
[guest]
2022-01-03 01시48분
@이승준 답변 정말 감사드립니다. ^^ 생각했던 것보다 이쪽 분야가 엄청 복잡다단하군요. ^^; 말씀해 주신 링크도 참고해서 다양한 빌드 버전을 얻어 테스트를 좀 더 해보겠습니다. (알려주시지 않았다면 그런게 있었는지 평생 몰랐을 듯싶군요. ^^)
정성태

... 106  107  108  [109]  110  111  112  113  114  115  116  117  118  119  120  ...
NoWriterDateCnt.TitleFile(s)
11199정성태5/16/201721144.NET Framework: 657. CultureInfo.GetCultures가 반환하는 값
11198정성태5/10/201722667.NET Framework: 656. Windows Forms의 오류(Exception) 처리 방법에 대한 차이점 설명
11197정성태5/8/201719546개발 환경 구성: 315. VHD 파일의 최소 크기파일 다운로드1
11196정성태5/4/201720755오류 유형: 384. Msvm_ImageManagementService WMI 객체를 사용할 때 오류 상황 정리 [1]
11195정성태5/3/201721049.NET Framework: 655. .NET Framework 4.7 릴리스
11194정성태5/3/201723267오류 유형: 383. net use 명령어로 네트워크 드라이브 연결 시 "System error 67 has occurred." 오류 발생
11193정성태5/3/201721590Windows: 141. 설치된 Windows로부터 설치 이미지를 만드는 방법
11192정성태5/2/201722144Windows: 140. unattended.xml/autounattend.xml 파일을 마련하는 방법
11191정성태5/2/201722833Windows: 139. Dell Venue 8 Pro 태블릿에 USB를 이용한 윈도우 운영체제 설치 방법
11190정성태5/2/201728179Windows: 138. Windows 운영체제의 ISO 설치 파일에 미리 Device driver를 준비하는 방법
11189정성태5/2/201720226Windows: 137. Windows 7 USB/DVD DOWNLOAD TOOL로 98%에서 실패하는 경우
11188정성태4/27/201722686VC++: 118. Win32 HANDLE 자료형의 이모저모 [1]
11187정성태4/26/201723241개발 환경 구성: 314. C# - PowerPoint 확장 Add-in 만드는 방법 [1]파일 다운로드1
11186정성태4/24/201721018VS.NET IDE: 117. Visual Studio 확장(VSIX)을 이용해 사용자 매크로를 추가하는 방법 [1]파일 다운로드1
11185정성태4/22/201718957VS.NET IDE: 116. Visual Studio 확장(VSIX)을 이용해 사용자 메뉴 추가하는 방법 (2) - 동적 메뉴 구성파일 다운로드1
11184정성태4/21/201720566VS.NET IDE: 115. Visual Studio 확장(VSIX)을 이용해 사용자 메뉴 추가하는 방법파일 다운로드1
11183정성태4/19/201719410.NET Framework: 654. UWP 앱에서 FolderPicker 사용 시 유의 사항파일 다운로드1
11182정성태4/19/201723425개발 환경 구성: 313. Nuget Facebook 라이브러리를 이용해 ASP.NET 웹 폼과 로그인 연동하는 방법
11181정성태4/18/201720349개발 환경 구성: 312. Azure Web Role의 AppPool 실행 권한을 Local System으로 바꾸는 방법
11180정성태4/16/201723378Java: 18. Java의 Memory Mapped File 자원 반환이 안 되는 문제
11179정성태4/13/201716515기타: 64. SVG Converter 스토어 앱 개인정보 보호 정책 안내
11178정성태4/10/201718666개발 환경 구성: 311. COM+ 관리자의 DCOM 구성에 나오는 기준
11177정성태4/7/201719149.NET Framework: 653. C# 7 새로운 문법(1) - 더욱 편리해진 Out 변수 사용파일 다운로드1
11176정성태4/5/201716147VC++: 117. Visual Studio - ATL COM 개체를 단위 테스트 하는 방법
11175정성태4/5/201725896.NET Framework: 652. C# 개발자를 위한 C++ COM 객체의 기본 구현 방식 설명파일 다운로드1
11174정성태4/3/201719404VC++: 116. Visual Studio 단위 테스트 - Failed to set up the execution context to run the test
... 106  107  108  [109]  110  111  112  113  114  115  116  117  118  119  120  ...