Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

(시리즈 글이 24개 있습니다.)
.NET Framework: 1129. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 인코딩 예제(encode_video.c)
; https://www.sysnet.pe.kr/2/0/12898

.NET Framework: 1134. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c)
; https://www.sysnet.pe.kr/2/0/12924

.NET Framework: 1135. C# - ffmpeg(FFmpeg.AutoGen)로 하드웨어 가속기를 이용한 비디오 디코딩 예제(hw_decode.c)
; https://www.sysnet.pe.kr/2/0/12932

.NET Framework: 1136. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 MP2 오디오 파일 디코딩 예제(decode_audio.c)
; https://www.sysnet.pe.kr/2/0/12933

.NET Framework: 1137. ffmpeg의 파일 해시 예제(ffhash.c)를 C#으로 포팅
; https://www.sysnet.pe.kr/2/0/12935

.NET Framework: 1138. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 멀티미디어 파일의 메타데이터를 보여주는 예제(metadata.c)
; https://www.sysnet.pe.kr/2/0/12936

.NET Framework: 1139. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 오디오(mp2) 인코딩하는 예제(encode_audio.c)
; https://www.sysnet.pe.kr/2/0/12937

.NET Framework: 1147. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 오디오 필터링 예제(filtering_audio.c)
; https://www.sysnet.pe.kr/2/0/12951

.NET Framework: 1148. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 오디오 필터 예제(filter_audio.c)
; https://www.sysnet.pe.kr/2/0/12952

.NET Framework: 1150. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c) - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/12959

개발 환경 구성: 637. ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c) - 세 번째 이야기
; https://www.sysnet.pe.kr/2/0/12960

.NET Framework: 1151. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 프레임의 크기 및 포맷 변경 예제(scaling_video.c)
; https://www.sysnet.pe.kr/2/0/12961

.NET Framework: 1153. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 avio_reading.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12964

.NET Framework: 1157. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 muxing.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12971

.NET Framework: 1159. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 qsvdec.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12975

.NET Framework: 1161. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 resampling_audio.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12978

.NET Framework: 1166. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 filtering_video.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12984

.NET Framework: 1169. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 demuxing_decoding.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12987

.NET Framework: 1170. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 transcode_aac.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12991

.NET Framework: 1178. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 http_multiclient.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13002

.NET Framework: 1180. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 remuxing.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13006

.NET Framework: 1188. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 transcoding.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13023

.NET Framework: 1190. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 vaapi_encode.c, vaapi_transcode.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13025

.NET Framework: 1191. C 언어로 작성된 FFmpeg Examples의 C# 포팅 전체 소스 코드
; https://www.sysnet.pe.kr/2/0/13026




C# - ffmpeg(FFmpeg.AutoGen)를 이용한 오디오 필터 예제(filter_audio.c)

지난 예제에 이어,

C# - ffmpeg(FFmpeg.AutoGen)를 이용한 오디오 필터링 예제(filtering_audio.c)
; https://www.sysnet.pe.kr/2/0/12951

이번에는 ffmpeg 예제 중 "filter_audio.c" 파일을 FFmpeg.AutoGen으로 포팅하겠습니다.

using FFmpeg.AutoGen;
using FFmpeg.AutoGen.Example;
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;

namespace FFmpegApp1
{
    internal unsafe class Program
    {
        const int INPUT_SAMPLERATE = 48000;
        const AVSampleFormat INPUT_FORMAT = AVSampleFormat.AV_SAMPLE_FMT_FLTP;
        const int INPUT_CHANNEL_LAYOUT = ffmpeg.AV_CH_LAYOUT_5POINT0;
        const float VOLUME_VAL = 0.90f;
        const int FRAME_SIZE = 1024;

        static int Main(string[] args)
        {
            FFmpegBinariesHelper.RegisterFFmpegBinaries();

#if DEBUG
            Console.WriteLine("Current directory: " + Environment.CurrentDirectory);
            Console.WriteLine("Running in {0}-bit mode.", Environment.Is64BitProcess ? "64" : "32");
            Console.WriteLine($"FFmpeg version info: {ffmpeg.av_version_info()}");
#endif
            Console.WriteLine();

            AVFilterGraph* graph;
            AVFilterContext* src;
            AVFilterContext* sink;
            AVFrame* frame;
            byte* errstr = stackalloc byte[1024];
            float duration;
            int err, nb_frames, i;

            duration = 20.0f;

            nb_frames = (int)(duration * INPUT_SAMPLERATE / FRAME_SIZE);
            if (nb_frames <= 0)
            {
                Console.WriteLine($"Invalid duration: {duration}");
                return 1;
            }

            frame = ffmpeg.av_frame_alloc();
            if (frame == null)
            {
                Console.WriteLine("Error allocating the frame");
                return 1;
            }

            do
            {
                err = init_filter_graph(&graph, &src, &sink);
                if (err < 0)
                {
                    Console.WriteLine("Unable to init filter graph:");
                    break;
                }

                for (i = 0; i < nb_frames; i++)
                {
                    err = get_input(frame, i);
                    if (err < 0)
                    {
                        Console.WriteLine("Error generating input frame:");
                        break;
                    }

                    err = ffmpeg.av_buffersrc_add_frame(src, frame);
                    if (err < 0)
                    {
                        ffmpeg.av_frame_unref(frame);
                        Console.WriteLine("Error submitting the frame to the filtergraph:");
                        break;
                    }

                    MD5 md5 = MD5.Create();

                    while ((err = ffmpeg.av_buffersink_get_frame(sink, frame)) >= 0)
                    {
                        err = process_output(md5, frame);
                        if (err < 0)
                        {
                            Console.WriteLine("Error processing the filtered frame:");
                            break;
                        }

                        ffmpeg.av_frame_unref(frame);
                    }

                    if (err == ffmpeg.AVERROR(ffmpeg.EAGAIN))
                    {
                        continue;
                    }
                    else if (err == ffmpeg.AVERROR_EOF)
                    {
                        break;
                    }
                    else if (err < 0)
                    {
                        Console.WriteLine("Error filtering the data:");
                        break;
                    }
                }

            } while (false);

            if (graph != null)
            {
                ffmpeg.avfilter_graph_free(&graph);
            }

            if (frame != null)
            {
                ffmpeg.av_frame_free(&frame);
            }

            if (err < 0 && err != ffmpeg.AVERROR(ffmpeg.EAGAIN))
            {
                ffmpeg.av_strerror(err, errstr, 1024);

                string result = Marshal.PtrToStringAnsi(new IntPtr(errstr), getStringSize(errstr, 1024));
                Console.WriteLine(result);
                return 1;
            }

            return 0;
        }


        private static unsafe int init_filter_graph(AVFilterGraph** graph, AVFilterContext** src, AVFilterContext** sink)
        {
            AVFilterGraph* filter_graph;
            AVFilterContext* abuffer_ctx = null;
            AVFilter* abuffer = null;
            AVFilterContext* volume_ctx = null;
            AVFilter* volume = null;
            AVFilterContext* aformat_ctx = null;
            AVFilter* aformat = null;
            AVFilterContext* abuffersink_ctx = null;
            AVFilter* abuffersink = null;

            AVDictionary* options_dict = null;
            byte* ch_layout = stackalloc byte[64];

            int err = 0;

            filter_graph = ffmpeg.avfilter_graph_alloc();
            if (filter_graph == null)
            {
                Console.WriteLine("Unable to create filter graph.");
                return ffmpeg.AVERROR(ffmpeg.ENOMEM);
            }


            abuffer = ffmpeg.avfilter_get_by_name("abuffer");
            if (abuffer == null)
            {
                Console.WriteLine("Could not find the abuffer filter.");
                return ffmpeg.AVERROR_FILTER_NOT_FOUND;
            }

            abuffer_ctx = ffmpeg.avfilter_graph_alloc_filter(filter_graph, abuffer, "src");
            if (abuffer_ctx == null)
            {
                Console.WriteLine("Could not allocate the abuffer instance.");
                return ffmpeg.AVERROR(ffmpeg.ENOMEM);
            }

            ffmpeg.av_get_channel_layout_string(ch_layout, 64, 0, INPUT_CHANNEL_LAYOUT);

            string ch_layout_value = Marshal.PtrToStringAnsi(new IntPtr(ch_layout), getStringSize(ch_layout, 64));
            err = ffmpeg.av_opt_set(abuffer_ctx, "channel_layout", ch_layout_value, ffmpeg.AV_OPT_SEARCH_CHILDREN);
            err = ffmpeg.av_opt_set(abuffer_ctx, "sample_fmt", ffmpeg.av_get_sample_fmt_name(INPUT_FORMAT), ffmpeg.AV_OPT_SEARCH_CHILDREN);
            err = ffmpeg.av_opt_set_q(abuffer_ctx, "time_base", new AVRational { num = 1, den = INPUT_SAMPLERATE }, ffmpeg.AV_OPT_SEARCH_CHILDREN);
            err = ffmpeg.av_opt_set_int(abuffer_ctx, "sample_rate", INPUT_SAMPLERATE, ffmpeg.AV_OPT_SEARCH_CHILDREN);

            err = ffmpeg.avfilter_init_str(abuffer_ctx, null);
            if (err < 0)
            {
                Console.WriteLine("Could not initialze the abuffer filter.");
                return err;
            }

            volume = ffmpeg.avfilter_get_by_name("volume");
            if (volume == null)
            {
                Console.WriteLine("Could not find the volume filter.");
                return ffmpeg.AVERROR_FILTER_NOT_FOUND;
            }

            volume_ctx = ffmpeg.avfilter_graph_alloc_filter(filter_graph, volume, "volume");
            if (volume_ctx == null)
            {
                Console.WriteLine("Could not allocate the volume instance.");
                return ffmpeg.AVERROR(ffmpeg.ENOMEM);
            }

            ffmpeg.av_dict_set(&options_dict, "volume", $"{VOLUME_VAL:F}", 0);
            err = ffmpeg.avfilter_init_dict(volume_ctx, &options_dict);
            ffmpeg.av_dict_free(&options_dict);
            if (err < 0)
            {
                Console.WriteLine("Could not initialze the volume filter.");
                return err;
            }

            aformat = ffmpeg.avfilter_get_by_name("aformat");
            if (aformat == null)
            {
                Console.WriteLine("Could not find the aformat filter.");
                return ffmpeg.AVERROR_FILTER_NOT_FOUND;
            }

            aformat_ctx = ffmpeg.avfilter_graph_alloc_filter(filter_graph, aformat, "aformat");
            if (aformat_ctx == null)
            {
                Console.WriteLine("Could not allocate the aformat instance.");
                return ffmpeg.AVERROR(ffmpeg.ENOMEM);
            }

            string options_str = $"sample_fmts={ffmpeg.av_get_sample_fmt_name(AVSampleFormat.AV_SAMPLE_FMT_S16)}:sample_rates=44100:channel_layouts=0x{ffmpeg.AV_CH_LAYOUT_STEREO:x}";
            err = ffmpeg.avfilter_init_str(aformat_ctx, options_str);
            if (err < 0)
            {
                ffmpeg.av_log(null, ffmpeg.AV_LOG_ERROR, "Could not initialize the aformat filter.");
                return err;
            }

            abuffersink = ffmpeg.avfilter_get_by_name("abuffersink");
            if (abuffersink == null)
            {
                Console.WriteLine("Could not allocate the abuffersink instance.");
                return ffmpeg.AVERROR(ffmpeg.ENOMEM);
            }

            abuffersink_ctx = ffmpeg.avfilter_graph_alloc_filter(filter_graph, abuffersink, "sink");
            if (abuffersink_ctx == null)
            {
                Console.WriteLine("Could not initialize the abuffersink instance.");
                return err;
            }

            err = ffmpeg.avfilter_init_str(abuffersink_ctx, null);
            if (err < 0)
            {
                Console.WriteLine("Could not initialize the abuffersink instance.");
                return err;
            }

            err = ffmpeg.avfilter_link(abuffer_ctx, 0, volume_ctx, 0);
            if (err >= 0)
            {
                err = ffmpeg.avfilter_link(volume_ctx, 0, aformat_ctx, 0);
            }

            if (err >= 0)
            {
                err = ffmpeg.avfilter_link(aformat_ctx, 0, abuffersink_ctx, 0);
            }

            if (err < 0)
            {
                Console.WriteLine("Error connecting filters.");
                return err;
            }

            err = ffmpeg.avfilter_graph_config(filter_graph, null);
            if (err < 0)
            {
                ffmpeg.av_log(null, ffmpeg.AV_LOG_ERROR, "Error configuring the filter graph");
                return err;
            }

            *graph = filter_graph;
            *src = abuffer_ctx;
            *sink = abuffersink_ctx;

            return 0;
        }

        private static int getStringSize(byte* buffer, int length)
        {
            for (int i = 0; i < length; i++)
            {
                if (buffer[i] == 0)
                {
                    return i;
                }
            }

            return 0;
        }

        static unsafe int process_output(MD5 md5, AVFrame* frame)
        {
            int planar = ffmpeg.av_sample_fmt_is_planar((AVSampleFormat)frame->format);
            int channels = ffmpeg.av_get_channel_layout_nb_channels(frame->channel_layout);
            int planes = planar != 0 ? channels : 1;
            int bps = ffmpeg.av_get_bytes_per_sample((AVSampleFormat)frame->format);
            int plane_size = bps * frame->nb_samples * (planar != 0 ? 1 : channels);
            int i;

            for (i = 0; i < planes; i++)
            {
                Span<byte> buffer = new Span<byte>(frame->extended_data[i], plane_size);
                byte[] computed = md5.ComputeHash(buffer.ToArray()); // ToArray: copy overhead

                Console.WriteLine(BitConverter.ToString(computed).Replace("-", ""));
            }
            
            return 0;
        }

        static unsafe int get_input(AVFrame* frame, int frame_num)
        {
            int err, i, j;

            frame->sample_rate = INPUT_SAMPLERATE;
            frame->format = (int)INPUT_FORMAT;
            frame->channel_layout = INPUT_CHANNEL_LAYOUT;
            frame->nb_samples = FRAME_SIZE;
            frame->pts = frame_num * FRAME_SIZE;

            err = ffmpeg.av_frame_get_buffer(frame, 0);
            if (err < 0)
            {
                return err;
            }

            for (i = 0; i < 5; i++)
            {
                float* data = (float*)frame->extended_data[i];

                for (j = 0; j < frame->nb_samples; j++)
                {
                    data[j] = (float)Math.Sin(2 * Math.PI * (frame_num + j) * (i + 1) / FRAME_SIZE);
                }
            }

            return 0;
        }
    }
}

위의 코드를 실행하면 get_input으로 사인파 데이터를 생성해 필터를 통과하면서 process_output에 의해 md5 checksum 데이터를 출력합니다.

아직 제 수준에서는 이런 예제까지는 필요 없는 것 같습니다. ^^

(첨부 파일은 이 글의 예제 코드를 포함합니다.)
(이 글의 소스 코드는 github에 올려져 있습니다.)




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







[최초 등록일: ]
[최종 수정일: 3/13/2022]

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

비밀번호

댓글 작성자
 




... 136  137  138  139  140  141  142  [143]  144  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1479정성태8/14/201325186오류 유형: 183. IIS - 바인딩 추가 시 Object reference not set to an instance of an object 오류 [5]
1478정성태8/14/201328491오류 유형: 182. 윈도우 정품 활성화 오류 - 0x80070426
1477정성태8/14/201327338VC++: 71. codeplex의 Project Austin - 실감나게 책장 넘기는 표현
1476정성태8/13/201335821디버깅 기술: 55. Windbg - 윈도우 핸들 테이블 (2)
1475정성태8/12/201334935.NET Framework: 377. 프로세스가 종료된 후에도 소켓이 살아있다면?파일 다운로드1
1474정성태8/10/201330989오류 유형: 181. 윈도우 8 - WmiPrvSE.exe 프로세스가 CPU 소비하는 현상
1473정성태8/8/201327793VC++: 70. Win32 socket이 Thread-safe할까? [1]파일 다운로드1
1472정성태8/7/201326242.NET Framework: 376. .NET 2.0의 유니코드 관련 문자열 비교 오류
1471정성태8/7/201331011개발 환경 구성: 193. .aspx 확장자 대신 .html 확장자를 사용하는 방법
1470정성태8/6/201327000오류 유형: 180. DISM.exe 0xc1510111 실행 오류
1469정성태8/6/201324062.NET Framework: 375. System.Net.Sockets.Socket이 Thread-safe할까? [2]파일 다운로드1
1468정성태8/6/201322211오류 유형: 179. IIS - No connection could be made because the target machine actively refused it 127.0.0.1:80
1467정성태8/5/201325644Java: 16. IE에 로드된 Java Applet의 다운로드 위치를 확인하는 방법
1466정성태7/27/201331225.NET Framework: 374. C#과 비교한 C++ STL vector 성능 [7]파일 다운로드1
1465정성태7/18/201334551기타: 33. C:\Windows\Installer 폴더의 용량 줄이기 [3]
1464정성태7/15/201322807오류 유형: 178. Visual Studio 2012 Express - ImportCardinalityMismatchException
1463정성태7/15/201323465오류 유형: 177. [DBNETLIB][ConnectionOpen (Connect()).]SQL Server does not exist or access denied.
1462정성태7/5/201326778VC++: 69. geek스러운 C/C++ 퀴즈 문제 [2]
1461정성태6/27/201343329.NET Framework: 373. C# 문자열의 인코딩이란?
1460정성태6/17/201325179.NET Framework: 372. PerformanceCounter - Category does not exist. [1]
1459정성태6/15/201328810Windows: 74. 한글 키가 아닌 영문 키를 기본으로 선택하는 방법 [5]
1458정성태6/13/201329666.NET Framework: 371. CAS Lock 방식이 과연 성능에 얼마나 도움이 될까요? [1]파일 다운로드1
1457정성태6/13/201325844개발 환경 구성: 192. "Probabilistic Programming and Bayesian Methods for Hackers" 예제 코드 실행 방법
1456정성태6/5/201334508.NET Framework: 370. C# - WebKit .NET 사용 [2]파일 다운로드1
1455정성태6/1/201328290.NET Framework: 369. ThreadPool.QueueUserWorkItem의 실행 지연 [4]파일 다운로드1
1454정성태5/31/201326328Java: 15. Java 7 Control Panel 실행시키는 방법
... 136  137  138  139  140  141  142  [143]  144  145  146  147  148  149  150  ...