Fix FFmpegNativeDecoder to Consider Color Range When Decoding Video

This commit is contained in:
copecone committed 2026-06-21 23:06:57 +09:00
1 parent 9bb2b85010
commit d48579435a
3 files changed
+420 -10

No files matched your search

+16 -10
View File
@@ -60,6 +60,9 @@ namespace ADOFAIRenderer.Util.FFmpeg
/// <summary>비디오 원본 코덱의 픽셀 포맷.</summary>
public AVPixelFormat PixelFormat => _pCodecContext != null ? _pCodecContext->pix_fmt : AVPixelFormat.AV_PIX_FMT_NONE;
/// <summary>비디오 원본 코덱의 색상 범위.</summary>
public AVColorRange ColorRange => _pCodecContext != null ? _pCodecContext->color_range : AVColorRange.AVCOL_RANGE_UNSPECIFIED;
public FFmpegNativeDecoder(string videoPath)
{
Open(videoPath);
@@ -255,7 +258,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
/// <param name="vflip">Unity 텍스처 시스템에 맞게 상하 flip을 적용할지 여부</param>
/// <param name="timestamp">출력된 프레임의 타임스탬프 (초)</param>
/// <returns>프레임을 성공적으로 디코딩하여 복사했으면 true, 재생이 끝났거나 실패했으면 false</returns>
public bool TryReadFrame(byte* outBuffer, int outStride, bool vflip, out double timestamp)
private bool TryReadFrame(byte* outBuffer, int outStride, bool vflip, out double timestamp)
{
timestamp = 0;
lock (_lock)
@@ -362,7 +365,8 @@ namespace ADOFAIRenderer.Util.FFmpeg
/// 비디오 원본이 YUV420p 계열(YUV420P, YUVJ420P)이면 CPU 컬러 변환(sws_scale)을 우회하고 메모리를 다이렉트로 복사하여 속도가 매우 빠릅니다.
/// 그 외 포맷일 경우 자동으로 YUV420p로 변환 후 복사합니다.
/// </summary>
public bool TryReadYUV420PFrame(
// ReSharper disable once InconsistentNaming
private bool TryReadYUV420PFrame(
byte* yBuffer, int yStride,
byte* uBuffer, int uStride,
byte* vBuffer, int vStride,
@@ -373,7 +377,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
{
if (!_isOpened || _disposed) return false;
AVFrame* frame = null;
AVFrame* frame;
if (_hasCachedFrame)
{
@@ -477,6 +481,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
}
}
// ReSharper disable once InconsistentNaming
public bool TryReadYUV420PFrame(
NativeArray<byte> yBuffer,
NativeArray<byte> uBuffer,
@@ -506,7 +511,8 @@ namespace ADOFAIRenderer.Util.FFmpeg
/// 비디오 원본이 NV12 계열이면 CPU 컬러 변환(sws_scale)을 우회하고 메모리를 다이렉트로 복사하여 속도가 매우 빠릅니다.
/// 그 외 포맷일 경우 자동으로 NV12로 변환 후 복사합니다.
/// </summary>
public bool TryReadNV12Frame(
// ReSharper disable once InconsistentNaming
private bool TryReadNV12Frame(
byte* yBuffer, int yStride,
byte* uvBuffer, int uvStride,
out double timestamp)
@@ -516,7 +522,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
{
if (!_isOpened || _disposed) return false;
AVFrame* frame = null;
AVFrame* frame;
if (_hasCachedFrame)
{
@@ -607,6 +613,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
}
}
// ReSharper disable once InconsistentNaming
public bool TryReadNV12Frame(
NativeArray<byte> yBuffer,
NativeArray<byte> uvBuffer,
@@ -633,12 +640,12 @@ namespace ADOFAIRenderer.Util.FFmpeg
/// </summary>
/// <param name="count">버릴 프레임 개수</param>
/// <returns>실제로 건너뛴 프레임 개수</returns>
public int SkipFrames(int count)
private void SkipFrames(int count)
{
lock (_lock)
{
if (!_isOpened || _disposed) return 0;
if (count <= 0) return 0;
if (!_isOpened || _disposed) return;
if (count <= 0) return;
int skipped = 0;
if (_hasCachedFrame)
@@ -678,7 +685,6 @@ namespace ADOFAIRenderer.Util.FFmpeg
throw new Exception($"프레임 건너뛰기 중 오류 발생: {GetFFmpegErrorString(ret)}");
}
}
return skipped;
}
}
@@ -696,7 +702,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
double targetFrameIndex = timeSeconds * FPS;
// 이미 해당 인덱스이고 매우 인접한 미래라면 seek 대신 skip 처리 (I-프레임 찾기 오버헤드 방지)
bool useSkip = targetFrameIndex >= _currentFrameIndex && (targetFrameIndex - _currentFrameIndex) < 60;
bool useSkip = targetFrameIndex >= _currentFrameIndex && targetFrameIndex - _currentFrameIndex < 60;
if (useSkip)
{
SkipFrames((int)(targetFrameIndex - _currentFrameIndex));