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분
@이승준 답변 정말 감사드립니다. ^^ 생각했던 것보다 이쪽 분야가 엄청 복잡다단하군요. ^^; 말씀해 주신 링크도 참고해서 다양한 빌드 버전을 얻어 테스트를 좀 더 해보겠습니다. (알려주시지 않았다면 그런게 있었는지 평생 몰랐을 듯싶군요. ^^)
정성태

... 91  92  93  94  95  96  97  98  99  100  [101]  102  103  104  105  ...
NoWriterDateCnt.TitleFile(s)
11407정성태12/18/201724206.NET Framework: 712. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드 + Direct2D 출력 + OpenCV [1]파일 다운로드1
11406정성태12/17/201746600.NET Framework: 711. C# - OpenCvSharp의 Mat 데이터 조작 방법 [5]파일 다운로드1
11405정성태12/17/201742577.NET Framework: 710. C# - OpenCvSharp을 이용한 Webcam 영상 처리 + Direct2D [1]파일 다운로드1
11404정성태12/16/201729892.NET Framework: 709. C# - OpenCvSharp을 이용한 동영상(avi, mp4, ...) 처리 + Direct2D [7]파일 다운로드1
11403정성태12/16/201732507.NET Framework: 708. C# - OpenCvSharp을 이용한 동영상(avi, mp4, ...) 처리 [3]파일 다운로드1
11402정성태12/15/201737165.NET Framework: 707. OpenCV 응용 프로그램을 C#으로 구현 - OpenCvSharp [2]파일 다운로드1
11401정성태12/15/201726106.NET Framework: 706. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드 + Direct2D 출력 [2]파일 다운로드1
11400정성태12/14/201728971.NET Framework: 705. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드 [9]파일 다운로드1
11399정성태12/13/201717592.NET Framework: 704. Win32 API의 UnionRect를 닷넷 BCL의 Rectangle.Union으로 바꿀 때 주의 사항
11398정성태12/13/201717797오류 유형: 442. ASP.NET Core Web Application (on .NET Framework) 프로젝트에서 외부 라이브러리 동적 로드 시 런타임 버전 문제파일 다운로드1
11397정성태12/12/201720389.NET Framework: 703. 양자 컴퓨팅을 위한 마이크로소프트의 Q# 언어
11396정성태12/8/201742753개발 환경 구성: 343. Visual Studio - 리눅스 용 프로젝트의 인텔리센스를 위한 헤더 파일 처리 방법 [3]
11395정성태12/8/201718616오류 유형: 441. 이벤트 로그 - Time Provider NtpClient: No valid response has been received from domain controller
11394정성태12/8/201718241개발 환경 구성: 342. 비주얼 스튜디오에서 실행하던 ASP.NET Core (.NET Framework) 응용 프로그램을 명령행에서 실행하는 방법
11393정성태12/7/201722792Windows: 145. 윈도우 10 빌드 17046부터 WSL에서 백그라운드 작업 지원 [5]
11392정성태12/7/201718055개발 환경 구성: 341. openSUSE에 닷넷 코어 설치
11391정성태12/7/201720908개발 환경 구성: 340. WSL을 이용해 윈도우 PC 1대에서 openSUSE 응용 프로그램을 Visual Studio로 개발하는 방법 [1]
11390정성태12/7/201729557개발 환경 구성: 339. WSL을 이용해 윈도우 PC 1대에서 Linux 응용 프로그램을 Visual Studio로 개발하는 방법 [6]
11389정성태12/7/201718232오류 유형: 440. .NET Core 오류 - 0x80131620 Unable to load DLL 'libuv'
11388정성태12/6/201721866개발 환경 구성: 338. WSL 또는 Ubuntu에 닷넷 코어 설치 [3]
11387정성태12/6/201722219오류 유형: 439. 이벤트 로그 - Data Sharing Service 서비스의 %%3239247874 오류 메시지
11386정성태12/5/201717787오류 유형: 438. Hyper-V - '...' failed to add device 'Virtual CD/DVD Disk'
11385정성태12/5/201730906VC++: 121. DXGI를 이용한 윈도우 화면 캡처 소스 코드(Visual C++) [16]파일 다운로드1
11384정성태12/5/201720184오류 유형: 437. Visual C++ - Cannot open include file: 'SDKDDKVer.h'
11383정성태12/4/201723298디버깅 기술: 110. 비동기 코드 실행 중 예외로 인한 ASP.NET 프로세스 비정상 종료 현상 [1]
11382정성태12/4/201721874오류 유형: 436. System.Data.SqlClient.SqlException (0x80131904): Connection Timeout Expired 예외 발생 시 "[Pre-Login] initialization=48; handshake=1944;" 값의 의미
... 91  92  93  94  95  96  97  98  99  100  [101]  102  103  104  105  ...