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