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

... 121  122  123  124  [125]  126  127  128  129  130  131  132  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
10830정성태8/12/201525470개발 환경 구성: 275. Web.config이 적용되지 않는 프로젝트에서 Razor 템플릿 파일의 C# 컴파일러 버전 제어 [1]
10829정성태8/10/201527584개발 환경 구성: 274. PowerShell/명령행에서 JDK/JRE를 무인(unattended)/자동 설치를 하는 방법 [3]
10828정성태8/10/201533060웹: 30. Edge 브라우저에서 "이 웹 사이트에는 Internet Explorer가 필요함" 단계를 없애는 방법 [1]
10827정성태7/8/201533878개발 환경 구성: 273. Visual Studio 2015에서 Github와 연동하는 방법 [3]
10826정성태7/8/201524225오류 유형: 301. The trust relationship between this workstation and the primary domain failed. - 두 번째 이야기
10825정성태7/8/201522907개발 환경 구성: 272. Visual Studio IDE 설치 없이 Visual Studio SDK 설치하는 방법
10824정성태7/7/201528547개발 환경 구성: 271. Team Foundation Server 2015 설치 방법 [1]
10823정성태7/7/201529319오류 유형: 300. SqlException (0x80131904): Unable to open the physical file
10822정성태7/7/201528142오류 유형: 299. The 'Visual C++ Project System Package' package did not load correctly.
10821정성태7/7/201521198오류 유형: 298. Unable to start debugging on the web server. IIS does not list a web site that matches the launched URL.
10820정성태7/7/201526927오류 유형: 297. HTTP Error 503. The service is unavailable. - 두 번째
10819정성태7/2/201530085오류 유형: 296. SQL Server Express 시작 오류 - error code 3417
10818정성태7/1/201529250오류 유형: 295. HTTP Error 503. The service is unavailable. [1]
10817정성태6/29/201533208.NET Framework: 523. C# 람다(Lambda)에서 변수 캡처 방식 [3]
10816정성태6/25/201528995.NET Framework: 522. 닷넷의 어셈블리 서명 데이터 확인 방법파일 다운로드1
10815정성태6/23/201527415Graphics: 1. 자네 나와 함께... UNITY 하지 않겠는가! [4]
10814정성태6/22/201525145.NET Framework: 521. Roslyn을 이용해 C# 문법 변형하기 (2) [5]
10813정성태6/21/201526249.NET Framework: 520. Roslyn을 이용해 C# 문법 변형하기 (1)
10812정성태6/20/201527140.NET Framework: 519. C# 6.0 오픈 소스 컴파일러 Roslyn - 빌드 및 테스트 방법 [1]
10811정성태6/20/201524246오류 유형: 294. OpenAuth 사용 시 System.Data.SqlClient.SqlException 예외가 Output 창에 출력되는 문제
10810정성태6/18/201523740개발 환경 구성: 270. Visual Studio에서 github 오픈 소스를 fork해서 테스트하는 방법 [1]
10809정성태6/18/201521489.NET Framework: 518. AllowPartiallyTrustedCallers 특성이 적용된 GAC 어셈블리에서 DynamicMethod의 calli 명령어 사용파일 다운로드1
10808정성태6/17/201523538.NET Framework: 517. calli IL 호출이 DllImport 호출보다 빠를까요? [1]파일 다운로드1
10807정성태6/16/201524990.NET Framework: 516. Microsoft.AspNet.Membership.OpenAuth 사용 시 "Local Database Runtime error occurred" 오류
10806정성태6/16/201542352.NET Framework: 515. OpenAuth.VerifyAuthentication 호출 시 The remote server returned an error: (400) Bad Request
10805정성태6/15/201524162Java: 17. 자바의 재미있는 상수 처리 방식
... 121  122  123  124  [125]  126  127  128  129  130  131  132  133  134  135  ...