Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
(연관된 글이 2개 있습니다.)
(시리즈 글이 8개 있습니다.)
.NET Framework: 288. FFmpeg.exe를 이용한 C# 동영상 인코더 예제
; https://www.sysnet.pe.kr/2/0/1210

개발 환경 구성: 622. vcpkg로 ffmpeg를 빌드하는 경우 생성될 구성 요소 제어하는 방법
; https://www.sysnet.pe.kr/2/0/12900

개발 환경 구성: 623. ffmpeg.exe를 사용해 비디오 파일의 이미지를 PGM(Portable Gray Map) 파일 포맷으로 출력하는 방법
; https://www.sysnet.pe.kr/2/0/12912

개발 환경 구성: 626. ffmpeg.exe를 사용해 비디오 파일을 MPEG1 포맷으로 변경하는 방법
; https://www.sysnet.pe.kr/2/0/12923

개발 환경 구성: 634. ffmpeg.exe - 기존 동영상 컨테이너에 다중 스트림을 추가하는 방법
; https://www.sysnet.pe.kr/2/0/12947

개발 환경 구성: 636. ffmpeg.exe를 이용해 planar 포맷의 데이터를 packed 형식으로 변환하는 방법?
; https://www.sysnet.pe.kr/2/0/12957

개발 환경 구성: 639. ffmpeg.exe - Intel Quick Sync Video(qsv)를 이용한 인코딩
; https://www.sysnet.pe.kr/2/0/12973

닷넷: 2365. C# - FFMpegCore를 이용한 MP4 동영상으로부터 MP3 음원 추출 예제
; https://www.sysnet.pe.kr/2/0/14015




C# - FFMpegCore를 이용한 MP4 동영상으로부터 MP3 음원 추출 예제

예전에 FFmpeg.AutoGen 패키지를 알아봤었는데요, 여전히 그게 선택지의 하나이긴 해도 이번에는 다른 걸로, 제목에 소개했듯이 FFMpegCore 패키지로 실습해 보겠습니다. ^^

FFMpegCore
; https://www.nuget.org/packages/FFMpegCore

rosenbjerg/FFMpegCore
; https://github.com/rosenbjerg/FFMpegCore

A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications. Supports both synchronous and asynchronous calls


repo의 설명에서는 "FFMpeg/FFProbe wrapper"라고 하는데요, 보다 더 엄밀히 말하면 "FFMpeg.exe/FFProbe.exe wrapper"가 맞습니다. ^^; 즉, ffmpeg.exe/ffproble.exe 파일을 실행한 후 그 출력 결과를 파싱한 결과를 이용하는 방식입니다. 환경 구성은 패키지를 설치 후,

Install-Package FFMpegCore

빌드하면 143KB 크기의 FFMpegCore.dll 파일이 함께 출력되는데요, 이후 실행 시 ffmpeg.exe/ffprobe.exe를 찾을 수 있도록 PATH 환경 변수에 있거나, 처음부터 EXE 파일이 있는 폴더에 그 파일들이 있으면 됩니다.




실습을 위해, Youtube에서 동영상을 하나 다운로드한 후, 오디오만을 분리해 mp3 파일로 저장하는 것이 이렇게나 간단합니다. ^^

string inputPath = @"c:\fftemp\test.mp4";
FFMpeg.ExtractAudio(inputPath, "test.mp3"); // mp3 확장자 필수!

// 오디오 파일의 확장자를 mp3가 아닌 다른 걸로 지정하면 예외가 발생합니다. 
/*
Unhandled exception. FFMpegCore.Exceptions.FFMpegException: Invalid output file. File extension should be '.mp3' required.
*/

벌써 제목에 소개한 기능의 설명이 끝났군요. ^^ 그래도 이대로는 아쉬우니 좀 더 살펴보겠습니다. 우선, Windows의 File Explorer에서 동영상 파일의 속성을 "Details" 패널을 통해 살펴봤더니 이런 정보가 나옵니다.

Length: 00:08:02
Frame width: 1920
Frame height: 1080
Frame rate: 29.97 frames/second
Data rate: 2356kbps
Total bitrate: 2484kbps

위의 정보를 FFMpegCore로 맞춰보면 "Total bitrate"를 제외하고는 대충 다음과 같이 구할 수 있습니다.

string inputPath = @"c:\fftemp\test.mp4";

var mediaInfo = await FFProbe.AnalyseAsync(inputPath);
Console.WriteLine($"Length: {mediaInfo.Duration}");

var videoStream = mediaInfo.PrimaryVideoStream;
Console.WriteLine($"Frame width: {videoStream?.Width}");
Console.WriteLine($"Frame height: {videoStream?.Height}");

Console.WriteLine($"Frame rate: {videoStream?.FrameRate:00.00} frames/second");
Console.WriteLine($"Data rate: {videoStream?.BitRate / 1000}kbps");

"Total bitrate"의 경우 이거저거 구해 조합해 보면 Video와 Audio의 Bitrate를 더한 값인 듯합니다. (실제로 그 값인지는 모르겠습니다. ^^;)

var videoStream = mediaInfo.PrimaryVideoStream;
var audioStream = mediaInfo.PrimaryAudioStream;

Console.WriteLine($"Total bitrate: {(videoStream?.BitRate + audioStream?.BitRate) / 1000}kbps");

그나저나, 저처럼 관련 업계의 지식이 빈약한 사람은 저 용어들 자체가 낯설기만 한데요, 위의 경우 Bit Rate가 왜 Data rate 값으로 평가되는지 좀 헷갈리는데 아래의 글에서 이에 대해 자세하게 설명하고 있습니다. ^^

Bit Rate vs Data Rate
; https://wolfcrow.com/bit-rate-vs-data-rate/

정리해 보면, 프레임의 인코딩 결과가 CBR(Constant Bit Rate)로 나온다면 Bit rate가 곧 Data rate에 해당할 수 있습니다. 하지만, VBR(Variable Bit Rat)로 프레임이 압축된다면 Bit rate가 프레임 별로 달라지므로 Data rate를 알 수 없고 그 순간까지의 "Average Bit Rate (평균 비트 전송률)"만을 알 수 있습니다. 그러다, 재생이 완료된 시점에는 전체 데이터를 시간으로 나눠 Data rate를 구할 수 있다고 합니다.

가령, VBR로 인코딩된 10초짜리 영상이 170MB라고 가정해 보면 각각 다음과 같은 수치를 구할 수 있습니다.

  • 데이터 전송률: 170MB / 10초 = 17MB/s
  • 평균 비트 전송률: 170MB/s

비록 저 값이 같게 나오긴 했지만, 엄밀하게는 구분이 됩니다. 즉, Data rate는 모든 데이터가 완전히 기록된 순간에 구할 수 있는 값이고, 평균 비트 전송률은 재생 도중에도 구할 수 있는 값입니다.




마지막으로, 비디오/오디오 정보의 출력과,

Console.WriteLine($"# of VideoStreams: {mediaInfo.VideoStreams.Count}");
foreach (var stream in mediaInfo.VideoStreams)
{
    Console.WriteLine($"\tStream: {stream.ColorSpace} - {stream.CodecName} ({stream.Width} x {stream.Height}), {stream.AvgFrameRate:00.00} frames/second, Data rate {stream.BitRate}");
}

Console.WriteLine();
Console.WriteLine($"# of AudioStreams: {mediaInfo.AudioStreams.Count}");
foreach (var stream in mediaInfo.AudioStreams)
{
    Console.WriteLine($"\tStream: {stream.CodecName}, {stream.BitRate} bit/s, {stream.SampleRateHz} Hz, {stream.Channels} channels");
}

다음과 같이 동영상의 특정 시점(예: 2분)에 대한 스냅샷 이미지를 PNG 파일로 저장하는 것도 가능합니다.

// 확장자를 png로 지정 (이 외의 확장자를 지정해도 무시하고 png로 저장)
FFMpeg.Snapshot(inputPath, "test.png", new Size(stream.Width, stream.Height), TimeSpan.FromMinutes(2));

그리고 이런 일련의 과정 중에는 ffmpeg.exe/ffprobe.exe가 자식 프로세스로 아래와 같은 식의 명령줄로 실행됩니다.

"ffprobe.exe" -version
"ffprobe.exe" -loglevel error -print_format json -show_format -sexagesimal -show_streams -show_chapters "c:\fftemp\test.mp4" 
"ffmpeg.exe" -formats

"ffmpeg.exe" -codecs
"ffmpeg.exe" -encoders
"ffmpeg.exe" -decoders

"ffmpeg.exe" -ss 00:01:00.000 -i "c:\fftemp\test.mp4" -map 0:0 -c:v png -vframes 1  "test.png" -y

어떠세요? 간단하기도 하고, 아주 자세하게 동영상을 제어할 필요가 없는 시나리오에서는 제법 유용할 듯합니다. ^^

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 9/23/2025]

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

비밀번호

댓글 작성자
 




... 61  62  63  64  65  66  67  [68]  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12356정성태10/7/202037892오류 유형: 662. ASP.NET Core와 500.19, 500.21 오류 (0x8007000d)
12355정성태10/3/202020136오류 유형: 661. Hyper-V Linux VM의 Internal 유형의 가상 Switch에 대한 IP 연결이 되지 않는 경우
12354정성태10/2/202035579오류 유형: 660. Web Deploy (msdeploy.axd) 실행 시 오류 기록 [1]
12353정성태10/2/202023216개발 환경 구성: 518. 비주얼 스튜디오에서 IIS 웹 서버로 "Web Deploy"를 이용해 배포하는 방법
12352정성태10/2/202026002개발 환경 구성: 517. Hyper-V Internal 네트워크에 NAT을 이용한 인터넷 연결 제공
12351정성태10/2/202024157오류 유형: 659. Nox 실행이 안 되는 경우 - Unable to bind to the underlying transport for ...
12350정성태9/25/202030386Windows: 175. 윈도우 환경에서 클라이언트 소켓의 최대 접속 수 [2]파일 다운로드1
12349정성태9/25/202023600Linux: 32. Ubuntu 20.04 - docker를 위한 tcp 바인딩 추가
12348정성태9/25/202024232오류 유형: 658. 리눅스 docker - Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
12347정성태9/25/202039309Windows: 174. WSL 2의 네트워크 통신 방법 [4]
12346정성태9/25/202022090오류 유형: 657. IIS - http://localhost 방문 시 Service Unavailable 503 오류 발생
12345정성태9/25/202023311오류 유형: 656. iisreset 실행 시 "Restart attempt failed." 오류가 발생하지만 웹 서비스는 정상적인 경우파일 다운로드1
12344정성태9/25/202024752Windows: 173. 서비스 관리자에 "IIS Admin Service"가 등록되어 있지 않다면?
12343정성태9/24/202036795.NET Framework: 945. C# - 닷넷 응용 프로그램에서 메모리 누수가 발생할 수 있는 패턴 [5]
12342정성태9/24/202025179디버깅 기술: 171. windbg - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법
12341정성태9/23/202021821.NET Framework: 944. C# - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법파일 다운로드1
12340정성태9/23/202021369.NET Framework: 943. WPF - WindowsFormsHost를 담은 윈도우 생성 시 메모리 누수
12339정성태9/21/202021334오류 유형: 655. 코어 모드의 윈도우는 GUI 모드의 윈도우로 교체가 안 됩니다.
12338정성태9/21/202023334오류 유형: 654. 우분투 설치 시 "CHS: Error 2001 reading sector ..." 오류 발생
12337정성태9/21/202023052오류 유형: 653. Windows - Time zone 설정을 바꿔도 반영이 안 되는 경우
12336정성태9/21/202027867.NET Framework: 942. C# - WOL(Wake On Lan) 구현
12335정성태9/21/202038329Linux: 31. 우분투 20.04 초기 설정 - 고정 IP 및 SSH 설치
12334정성태9/21/202022707오류 유형: 652. windbg - !py 확장 명령어 실행 시 "failed to find python interpreter"
12333정성태9/20/202023394.NET Framework: 941. C# - 전위/후위 증감 연산자에 대한 오버로딩 구현 (2)
12332정성태9/18/202025129.NET Framework: 940. C# - Windows Forms ListView와 DataGridView의 예제 코드파일 다운로드1
12331정성태9/18/202024853오류 유형: 651. repadmin /syncall - 0x80090322 The target principal name is incorrect.
... 61  62  63  64  65  66  67  [68]  69  70  71  72  73  74  75  ...