SHA256
Update FFmpegNativeEncoder to Implement Direct API Encoding
This commit is contained in:
1 parent
bfdfa9beb7
commit
1c984176cd
1 file changed
+87
-1
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using FFmpeg.AutoGen;
|
using FFmpeg.AutoGen;
|
||||||
using HarmonyLib;
|
|
||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
|
using Unity.Collections.LowLevel.Unsafe;
|
||||||
|
|
||||||
namespace ADOFAIRenderer.Util.FFmpeg
|
namespace ADOFAIRenderer.Util.FFmpeg
|
||||||
{
|
{
|
||||||
@@ -172,12 +172,36 @@ namespace ADOFAIRenderer.Util.FFmpeg
|
|||||||
|
|
||||||
public void WriteFrameFromBuffer(byte* buffer)
|
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)
|
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()
|
private void WriteFrame()
|
||||||
@@ -198,7 +222,69 @@ namespace ADOFAIRenderer.Util.FFmpeg
|
|||||||
|
|
||||||
private void SendFrameAndWritePackets(AVFrame* pFrame)
|
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()
|
public void Dispose()
|
||||||
|
|||||||
Reference in new issue
Block a user