성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 그냥 RSS Reader 기능과 약간의 UI 편의성 때문에 사용...
[이종효] 오래된 소프트웨어는 보안 위협이 되기도 합니다. 혹시 어떤 기능...
[정성태] @Keystroke IEEE의 문서를 소개해 주시다니... +_...
[손민수 (Keystroke)] 괜히 듀얼채널 구성할 때 한번에 같은 제품 사라고 하는 것이 아...
[정성태] 전각(Full-width)/반각(Half-width) 기능을 토...
[정성태] Vector에 대한 내용은 없습니다. Vector가 닷넷 BCL...
[orion] 글 읽고 찾아보니 디자인 타임에는 InitializeCompon...
[orion] 연휴 전에 재현 프로젝트 올리자 생각해 놓고 여의치 않아서 못 ...
[정성태] 아래의 글에 정리했으니 참고하세요. C# - Typed D...
[정성태] 간단한 재현 프로젝트라도 있을까요? 저런 식으로 설명만 해...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - ffmpeg(FFmpeg.AutoGen)를 이용해 오디오(mp2) 인코딩하는 예제(encode_audio.c)</h1> <p> 지난 예제에 이어,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - ffmpeg(FFmpeg.AutoGen)를 이용해 멀티미디어 파일의 메타데이터를 보여주는 예제(metadata.c) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12936'>https://www.sysnet.pe.kr/2/0/12936</a> </pre> <br /> 이번에는 <a target='tab' href='https://ffmpeg.org/doxygen/trunk/examples.html'>ffmpeg 예제</a> 중 "<a target='tab' href='https://ffmpeg.org/doxygen/trunk/encode_audio_8c-example.html'>encode_audio.c</a>" 파일을 FFmpeg.AutoGen으로 포팅하겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using FFmpeg.AutoGen; using FFmpeg.AutoGen.Example; using System; using System.IO; namespace FFmpegApp1 { internal unsafe class Program { static void 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(); Console.WriteLine($"LIBAVFORMAT Version: {ffmpeg.LIBAVFORMAT_VERSION_MAJOR}.{ffmpeg.LIBAVFORMAT_VERSION_MINOR}"); encode_audio(@"C:\temp\output\test.mp2"); } private static void encode_audio(string filename) { AVCodec* codec; AVCodecContext* c = null; AVFrame* frame = null; AVPacket* pkt = null; int i, j, k, ret; short* samples; float t, tincr; /* find the MP2 encoder */ codec = ffmpeg.avcodec_find_encoder(AVCodecID.AV_CODEC_ID_MP2); if (codec == null) { Console.WriteLine("Codec not found"); return; } do { c = ffmpeg.avcodec_alloc_context3(codec); if (c == null) { Console.WriteLine("Could not allocate audio codec context"); break; } /* put sample parameters */ c->bit_rate = 64000; /* check that the encoder supports s16 pcm input */ c->sample_fmt = AVSampleFormat.AV_SAMPLE_FMT_S16; if (check_sample_fmt(codec, c->sample_fmt) == 0) { Console.WriteLine($"Encoder does not support sample format {ffmpeg.av_get_sample_fmt_name(c->sample_fmt)}"); break; } /* select other audio parameters supported by the encoder */ c->sample_rate = select_sample_rate(codec); c->channel_layout = select_channel_layout(codec); c->channels = ffmpeg.av_get_channel_layout_nb_channels(c->channel_layout); /* open it */ if (ffmpeg.avcodec_open2(c, codec, null) < 0) { Console.WriteLine("Could not open codec"); break; } using FileStream f = System.IO.File.OpenWrite(filename); /* packet for holding encoded output */ pkt = ffmpeg.av_packet_alloc(); if (pkt == null) { Console.WriteLine( "could not allocate the packet"); break; } /* frame containing input raw audio */ frame = ffmpeg.av_frame_alloc(); if (frame == null) { Console.WriteLine("Could not allocate audio frame"); break; } frame->nb_samples = c->frame_size; frame->format = (int)c->sample_fmt; frame->channel_layout = c->channel_layout; /* allocate the data buffers */ ret = ffmpeg.av_frame_get_buffer(frame, 0); if (ret < 0) { Console.WriteLine("Could not allocate audio data buffers"); break; } /* encode a single tone sound */ t = 0; tincr = (float)(2 * Math.PI * 440.0 / c->sample_rate); for (i = 0; i < 200; i++) { /* make sure the frame is writable -- makes a copy if the encoder * kept a reference internally */ ret = ffmpeg.av_frame_make_writable(frame); if (ret < 0) { break; } samples = (short *)frame->data[0]; for (j = 0; j < c->frame_size; j++) { samples[2 * j] = (short)(Math.Sin(t) * 10000); for (k = 1; k < c->channels; k++) { samples[2 * j + k] = samples[2 * j]; } t += tincr; } encode(c, frame, pkt, f); } /* flush the encoder */ encode(c, null, pkt, f); } while (false); if (frame != null) { ffmpeg.av_frame_free(&frame); } if (pkt != null) { ffmpeg.av_packet_free(&pkt); } if (c != null) { ffmpeg.avcodec_free_context(&c); } } /* check that a given sample format is supported by the encoder */ static unsafe int check_sample_fmt(AVCodec* codec, AVSampleFormat sample_fmt) { AVSampleFormat* p = codec->sample_fmts; while (*p != AVSampleFormat.AV_SAMPLE_FMT_NONE) { if (*p == sample_fmt) { return 1; } p++; } return 0; } /* just pick the highest supported samplerate */ static unsafe int select_sample_rate(AVCodec* codec) { int* p; int best_samplerate = 0; if (codec->supported_samplerates == null) { return 44100; } p = codec->supported_samplerates; while (*p != 0) { if (best_samplerate == 0 || Math.Abs(44100 - *p) < Math.Abs(44100 - best_samplerate)) { best_samplerate = *p; } p++; } return best_samplerate; } /* select layout with the highest channel count */ static unsafe ulong select_channel_layout(AVCodec* codec) { ulong* p; ulong best_ch_layout = 0; int best_nb_channels = 0; if (codec->channel_layouts == null) { return ffmpeg.AV_CH_LAYOUT_STEREO; } p = codec->channel_layouts; while (*p != 0) { int nb_channels = ffmpeg.av_get_channel_layout_nb_channels(*p); if (nb_channels > best_nb_channels) { best_ch_layout = *p; best_nb_channels = nb_channels; } p++; } return best_ch_layout; } static bool encode(AVCodecContext* ctx, AVFrame* frame, AVPacket* pkt, FileStream output) { int ret; /* send the frame for encoding */ ret = ffmpeg.avcodec_send_frame(ctx, frame); if (ret < 0) { Console.WriteLine("Error sending the frame to the encoder"); return false; } /* read all the available output packets (in general there may be any * number of them */ while (ret >= 0) { ret = ffmpeg.avcodec_receive_packet(ctx, pkt); if (ret == ffmpeg.AVERROR(ffmpeg.EAGAIN) || ret == ffmpeg.AVERROR_EOF) { return true; } else if (ret < 0) { Console.WriteLine("Error encoding audio frame"); return false; } ReadOnlySpan<byte> buffer = new ReadOnlySpan<byte>(pkt->data, pkt->size); output.Write(buffer); ffmpeg.av_packet_unref(pkt); } return true; } } } </pre> <br /> 위의 코드를 실행하면 mp2 포맷의 오디오 파일이 생성됩니다. 그 파일의 포맷을 검사하면,<br /> <br /> <a name='mp2_probe'></a> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\output> <span style='color: blue; font-weight: bold'>ffprobe test.mp2</span> ffprobe version 4.4.1 Copyright (c) 2007-2021 the FFmpeg developers built with Microsoft (R) C/C++ Optimizing Compiler Version 19.30.30705 for x64 configuration: ...[생략]... --extra-cxxflags=-MD libavutil 56. 70.100 / 56. 70.100 ...[생략]... libpostproc 55. 9.100 / 55. 9.100 [mp3 @ 0000022DD9812140] Estimating duration from bitrate, this may be inaccurate Input #0, mp3, from 'test.mp2': Duration: 00:00:05.22, start: 0.000000, bitrate: 64 kb/s Stream #0:0: <span style='color: blue; font-weight: bold'>Audio: mp2</span>, 44100 Hz, stereo, fltp, 64 kb/s </pre> <br /> mp2라고 나오고, 실제로 미디어 플레이어를 이용해 재생하면 "뚜~~~" 소리가 5.22초 동안 재생됩니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1888&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> (<a target='tab' href='https://github.com/stjeong/ffmpeg_autogen_cs/tree/master/encode_audio'>이 글의 소스 코드는 github에 올려</a>져 있습니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
8053
(왼쪽의 숫자를 입력해야 합니다.)