Refactor FFmpegNativeEncoder

This commit is contained in:
copecone committed 2026-07-11 00:42:00 +09:00
1 parent 739d9314fe
commit 72648b4286
1 file changed
+18 -38
+18 -38
View File
@@ -1144,7 +1144,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
ffmpeg.av_frame_unref(_pHwFrame);
try
{
int ret = ffmpeg.av_hwframe_get_buffer(_pCodecContext->hw_frames_ctx, _pHwFrame, 0);
var ret = ffmpeg.av_hwframe_get_buffer(_pCodecContext->hw_frames_ctx, _pHwFrame, 0);
if (ret < 0)
throw new Exception($"QSV 하드웨어 프레임 버퍼 할당 실패 — {GetFFmpegErrorString(ret)} (Code: {ret})");
@@ -1217,7 +1217,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
ffmpeg.av_frame_unref(_pHwFrame);
try
{
int ret = ffmpeg.av_hwframe_get_buffer(_pCodecContext->hw_frames_ctx, _pHwFrame, 0);
var ret = ffmpeg.av_hwframe_get_buffer(_pCodecContext->hw_frames_ctx, _pHwFrame, 0);
if (ret < 0)
throw new Exception($"QSV 하드웨어 프레임 버퍼 할당 실패 — {GetFFmpegErrorString(ret)} (Code: {ret})");
@@ -1297,15 +1297,9 @@ namespace ADOFAIRenderer.Util.FFmpeg
// EAGAIN: 인코더가 더 많은 입력 프레임을 필요로 함 → 루프 종료
// EOF: 인코더 플러시 완료 (모든 지연 프레임 출력됨) → 루프 종료
if (response == ffmpeg.AVERROR(ffmpeg.EAGAIN) || response == ffmpeg.AVERROR_EOF)
{
break;
}
if (response == ffmpeg.AVERROR(ffmpeg.EAGAIN) || response == ffmpeg.AVERROR_EOF) break;
if (response < 0)
{
throw new Exception($"인코더에서 패킷을 수신하는 도중 에러가 발생했습니다. (Code: {response})");
}
// 코덱 타임베이스 → 스트림 타임베이스로 PTS/DTS 변환
ffmpeg.av_packet_rescale_ts(_pPacket, _pCodecContext->time_base, _pVideoStream->time_base);
@@ -1316,9 +1310,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
// 인터리빙하여 쓴다는 의미입니다. 비디오만 있어도 이 함수를 사용합니다.
response = ffmpeg.av_interleaved_write_frame(_pFormatContext, _pPacket);
if (response < 0)
{
throw new Exception($"패킷을 파일에 쓰는 도중 에러가 발생했습니다. (Code: {response})");
}
// 패킷의 데이터 참조를 해제하여 다음 receive_packet에서 재사용할 수 있게 합니다.
ffmpeg.av_packet_unref(_pPacket);
@@ -1365,7 +1357,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
catch (Exception ex)
{
// 플러시 과정 중 발생한 에러 기록
UnityEngine.Debug.LogError($"비디오 인코더 플러시 중 오류 발생: {ex.Message}");
Melon<RenderMod>.Logger.Error($"비디오 인코더 플러시 중 오류 발생: {ex.Message}");
}
// 1.5. 오디오 FIFO에 남은 샘플 플러시 + 오디오 인코더 플러시
@@ -1377,7 +1369,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
}
catch (Exception ex)
{
UnityEngine.Debug.LogError($"오디오 인코더 플러시 중 오류 발생: {ex.Message}");
Melon<RenderMod>.Logger.Error($"오디오 인코더 플러시 중 오류 발생: {ex.Message}");
}
}
@@ -1544,17 +1536,10 @@ namespace ADOFAIRenderer.Util.FFmpeg
// 인코더가 지원하는 샘플 포맷 중 첫 번째를 선택합니다.
// 대부분의 인코더는 AV_SAMPLE_FMT_FLTP(float planar)를 선호합니다.
AVSampleFormat encoderSampleFmt;
#pragma warning disable CS0618 // AVCodec.sample_fmts is deprecated but still functional; avcodec_get_supported_config() is the replacement
if (pAudioCodec->sample_fmts != null)
{
encoderSampleFmt = pAudioCodec->sample_fmts[0];
}
#pragma warning restore CS0618
else
{
encoderSampleFmt = AVSampleFormat.AV_SAMPLE_FMT_FLTP;
}
// AVCodec.sample_fmts is deprecated but still functional; avcodec_get_supported_config() is the replacement
#pragma warning disable CS0618
var encoderSampleFmt = pAudioCodec->sample_fmts != null ? pAudioCodec->sample_fmts[0] : AVSampleFormat.AV_SAMPLE_FMT_FLTP;
#pragma warning restore CS0618
_pAudioCodecContext->sample_rate = sampleRate;
_pAudioCodecContext->sample_fmt = encoderSampleFmt;
@@ -1717,15 +1702,15 @@ namespace ADOFAIRenderer.Util.FFmpeg
(byte**)&pConvertedFrame->data, numSamples,
&inputBuffer, numSamples);
if (convertedSamples < 0)
throw new Exception($"오디오 리샘플링 실패: {GetFFmpegErrorString(convertedSamples)} (Code: {convertedSamples})");
if (convertedSamples == 0) return;
switch (convertedSamples)
{
case < 0: throw new Exception($"오디오 리샘플링 실패: {GetFFmpegErrorString(convertedSamples)} (Code: {convertedSamples})");
case 0: return;
}
// ── 2. FIFO 버퍼에 추가 ──
var written = ffmpeg.av_audio_fifo_write(_pAudioFifo, (void**)&pConvertedFrame->data, convertedSamples);
if (written < convertedSamples)
throw new Exception("오디오 FIFO 쓰기 실패");
if (written < convertedSamples) throw new Exception("오디오 FIFO 쓰기 실패");
// ── 3. FIFO에서 frame_size 단위로 꺼내어 인코딩 ──
var frameSize = _pAudioCodecContext->frame_size > 0 ? _pAudioCodecContext->frame_size : 1024;
@@ -1735,8 +1720,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
_pAudioFrame->nb_samples = frameSize;
var read = ffmpeg.av_audio_fifo_read(_pAudioFifo, (void**)&_pAudioFrame->data, frameSize);
if (read < frameSize)
throw new Exception("오디오 FIFO 읽기 실패");
if (read < frameSize) throw new Exception("오디오 FIFO 읽기 실패");
_pAudioFrame->pts = _audioSampleIndex;
_audioSampleIndex += frameSize;
@@ -1767,12 +1751,8 @@ namespace ADOFAIRenderer.Util.FFmpeg
while (true)
{
response = ffmpeg.avcodec_receive_packet(_pAudioCodecContext, _pAudioPacket);
if (response == ffmpeg.AVERROR(ffmpeg.EAGAIN) || response == ffmpeg.AVERROR_EOF)
{
break;
}
if (response == ffmpeg.AVERROR(ffmpeg.EAGAIN) || response == ffmpeg.AVERROR_EOF) break;
if (response < 0)
{
throw new Exception($"오디오 인코더에서 패킷을 수신하는 도중 에러가 발생했습니다: {GetFFmpegErrorString(response)} (Code: {response})");