Update FFmpegNativeEncoder to Implement Direct API Encoding

This commit is contained in:
copecone committed 2026-06-02 19:49:51 +09:00
1 parent bfdfa9beb7
commit 1c984176cd
1 file changed
+87 -1
+87 -1
View File
@@ -1,7 +1,7 @@
using System;
using FFmpeg.AutoGen;
using HarmonyLib;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace ADOFAIRenderer.Util.FFmpeg
{
@@ -172,12 +172,36 @@ namespace ADOFAIRenderer.Util.FFmpeg
public void WriteFrameFromBuffer(byte* buffer)
{
if (!_isInitialized) throw new InvalidOperationException("인코더가 초기화되지 않았습니다.");
_pSrcFrame->data[0] = buffer;
_pSrcFrame->linesize[0] = _settings.Width * 4; // RGBA = 4 bytes per pixel
_pSrcFrame->width = _settings.Width;
_pSrcFrame->height = _settings.Height;
_pSrcFrame->format = (int)AVPixelFormat.AV_PIX_FMT_RGBA;
WriteFrame();
}
public void WriteFrameFromNativeBuffer(NativeArray<byte> buffer)
{
if (!_isInitialized) throw new InvalidOperationException("인코더가 초기화되지 않았습니다.");
WriteFrameFromBuffer((byte*)buffer.GetUnsafeReadOnlyPtr());
}
public void SendDataFromNativeBuffer(IntPtr pointer, int length)
{
if (!_isInitialized) throw new InvalidOperationException("인코더가 초기화되지 않았습니다.");
WriteFrameFromBuffer((byte*)pointer.ToPointer());
}
public void SendDataFromBuffer(byte[] buffer, int length)
{
if (!_isInitialized) throw new InvalidOperationException("인코더가 초기화되지 않았습니다.");
fixed (byte* pBuffer = buffer)
{
WriteFrameFromBuffer(pBuffer);
}
}
private void WriteFrame()
@@ -198,7 +222,69 @@ namespace ADOFAIRenderer.Util.FFmpeg
private void SendFrameAndWritePackets(AVFrame* pFrame)
{
int response = ffmpeg.avcodec_send_frame(_pCodecContext, pFrame);
if (response < 0)
{
throw new Exception($"인코더에 프레임을 전송하는 도중 에러가 발생했습니다. (Code: {response})");
}
AVPacket* pPacket = ffmpeg.av_packet_alloc();
try
{
while (true)
{
response = ffmpeg.avcodec_receive_packet(_pCodecContext, pPacket);
if (response == ffmpeg.AVERROR(ffmpeg.EAGAIN) || response == ffmpeg.AVERROR_EOF)
{
break;
}
else if (response < 0)
{
throw new Exception($"인코더에서 패킷을 수신하는 도중 에러가 발생했습니다. (Code: {response})");
}
// 스트림 타임베이스로 패킷 PTS/DTS 재조정
ffmpeg.av_packet_rescale_ts(pPacket, _pCodecContext->time_base, _pStream->time_base);
pPacket->stream_index = _pStream->index;
// 파일에 패킷 쓰기
response = ffmpeg.av_interleaved_write_frame(_pFormatContext, pPacket);
if (response < 0)
{
throw new Exception($"패킷을 파일에 쓰는 도중 에러가 발생했습니다. (Code: {response})");
}
ffmpeg.av_packet_unref(pPacket);
}
}
finally
{
ffmpeg.av_packet_free(&pPacket);
}
}
public void End()
{
if (!_isInitialized) return;
// 1. 지연된 프레임 플러시 (null 프레임 전송)
try
{
SendFrameAndWritePackets(null);
}
catch (Exception ex)
{
// 플러시 과정 중 발생한 에러 기록
UnityEngine.Debug.LogError($"인코더 플러시 중 오류 발생: {ex.Message}");
}
// 2. 트레일러 쓰기
if (_pFormatContext != null)
{
ffmpeg.av_write_trailer(_pFormatContext);
}
_isInitialized = false;
}
public void Dispose()