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 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()
|
||||
|
||||
Reference in new issue
Block a user