WIP
This commit is contained in:
@@ -117,8 +117,8 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\VavCore\VavCore.h" />
|
||||
<ClInclude Include="include\VavCore\VideoTypes.h" />
|
||||
<ClInclude Include="include\VavCore\IVideoDecoder.h" />
|
||||
<ClInclude Include="src\Common\VideoTypes.h" />
|
||||
<ClInclude Include="src\Decoder\IVideoDecoder.h" />
|
||||
<ClInclude Include="src\pch.h" />
|
||||
<ClInclude Include="src\Common\AdaptiveTypes.h" />
|
||||
<ClInclude Include="src\Decoder\AV1Decoder.h" />
|
||||
|
||||
@@ -126,9 +126,12 @@ bool NVDECAV1Decoder::Initialize(const VideoMetadata& metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check NVDEC availability
|
||||
if (!IsNVDECAvailable(metadata.width, metadata.height)) {
|
||||
LogError("NVDEC not available on this system");
|
||||
// Check NVDEC availability with ColorSpace compatibility check
|
||||
if (!IsNVDECAvailable(metadata.width, metadata.height, metadata.color_space)) {
|
||||
char debug_buf[256];
|
||||
sprintf_s(debug_buf, "NVDEC not available for this video format (%dx%d, ColorSpace=%d)",
|
||||
metadata.width, metadata.height, static_cast<int>(metadata.color_space));
|
||||
LogError(debug_buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -523,7 +526,7 @@ std::string NVDECAV1Decoder::GetVersion() const {
|
||||
return "NVDEC AV1 (CUDA Driver: " + std::to_string(driver_version) + ")";
|
||||
}
|
||||
|
||||
bool NVDECAV1Decoder::IsNVDECAvailable(uint32_t width, uint32_t height) const {
|
||||
bool NVDECAV1Decoder::IsNVDECAvailable(uint32_t width, uint32_t height, ColorSpace color_space) const {
|
||||
char debug_buf[256];
|
||||
|
||||
// Check if CUDA driver is available
|
||||
@@ -578,11 +581,36 @@ bool NVDECAV1Decoder::IsNVDECAvailable(uint32_t width, uint32_t height) const {
|
||||
}
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] Step 4: CUDA context created\n");
|
||||
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] Step 5: Checking AV1 decode capabilities...\n");
|
||||
// Map ColorSpace to NVDEC ChromaFormat
|
||||
cudaVideoChromaFormat chroma_format;
|
||||
const char* color_space_name;
|
||||
switch (color_space) {
|
||||
case ColorSpace::YUV420P:
|
||||
chroma_format = cudaVideoChromaFormat_420;
|
||||
color_space_name = "YUV420";
|
||||
break;
|
||||
case ColorSpace::YUV422P:
|
||||
chroma_format = cudaVideoChromaFormat_422;
|
||||
color_space_name = "YUV422";
|
||||
break;
|
||||
case ColorSpace::YUV444P:
|
||||
chroma_format = cudaVideoChromaFormat_444;
|
||||
color_space_name = "YUV444";
|
||||
break;
|
||||
default:
|
||||
sprintf_s(debug_buf, "[NVDECAV1Decoder::IsNVDECAvailable] FAILED: Unsupported ColorSpace %d\n", static_cast<int>(color_space));
|
||||
OutputDebugStringA(debug_buf);
|
||||
cuCtxDestroy(cuContext);
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf_s(debug_buf, "[NVDECAV1Decoder::IsNVDECAvailable] Step 5: Checking %s decode capabilities...\n", color_space_name);
|
||||
OutputDebugStringA(debug_buf);
|
||||
|
||||
CUVIDDECODECAPS decode_caps;
|
||||
memset(&decode_caps, 0, sizeof(decode_caps));
|
||||
decode_caps.eCodecType = cudaVideoCodec_AV1;
|
||||
decode_caps.eChromaFormat = cudaVideoChromaFormat_420;
|
||||
decode_caps.eChromaFormat = chroma_format;
|
||||
decode_caps.nBitDepthMinus8 = 0;
|
||||
|
||||
result = cuvidGetDecoderCaps(&decode_caps);
|
||||
@@ -595,12 +623,48 @@ bool NVDECAV1Decoder::IsNVDECAvailable(uint32_t width, uint32_t height) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf_s(debug_buf, "[NVDECAV1Decoder::IsNVDECAvailable] Step 5: AV1 decode caps - bIsSupported=%d, nMaxWidth=%d, nMaxHeight=%d\n",
|
||||
decode_caps.bIsSupported, decode_caps.nMaxWidth, decode_caps.nMaxHeight);
|
||||
sprintf_s(debug_buf, "[NVDECAV1Decoder::IsNVDECAvailable] Step 5: AV1 %s decode caps - bIsSupported=%d, nMaxWidth=%d, nMaxHeight=%d\n",
|
||||
color_space_name, decode_caps.bIsSupported, decode_caps.nMaxWidth, decode_caps.nMaxHeight);
|
||||
OutputDebugStringA(debug_buf);
|
||||
|
||||
if (!decode_caps.bIsSupported) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] FAILED: AV1 decoding is NOT supported by this GPU\n");
|
||||
sprintf_s(debug_buf, "[NVDECAV1Decoder::IsNVDECAvailable] FAILED: AV1 %s decoding is NOT supported by this GPU\n", color_space_name);
|
||||
OutputDebugStringA(debug_buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check supported output formats
|
||||
sprintf_s(debug_buf, "[NVDECAV1Decoder::IsNVDECAvailable] Step 6: Output format mask = 0x%X\n", decode_caps.nOutputFormatMask);
|
||||
OutputDebugStringA(debug_buf);
|
||||
|
||||
bool has_supported_output = false;
|
||||
if (decode_caps.nOutputFormatMask & (1 << cudaVideoSurfaceFormat_NV12)) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] - NV12 supported\n");
|
||||
has_supported_output = true;
|
||||
}
|
||||
if (decode_caps.nOutputFormatMask & (1 << cudaVideoSurfaceFormat_P016)) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] - P016 (10-bit 4:2:0) supported\n");
|
||||
has_supported_output = true;
|
||||
}
|
||||
if (decode_caps.nOutputFormatMask & (1 << cudaVideoSurfaceFormat_YUV444)) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] - YUV444 (8-bit 4:4:4) supported\n");
|
||||
has_supported_output = true;
|
||||
}
|
||||
if (decode_caps.nOutputFormatMask & (1 << cudaVideoSurfaceFormat_YUV444_16Bit)) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] - YUV444_16Bit (10-bit 4:4:4) supported\n");
|
||||
has_supported_output = true;
|
||||
}
|
||||
if (decode_caps.nOutputFormatMask & (1 << cudaVideoSurfaceFormat_NV16)) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] - NV16 (8-bit 4:2:2) supported\n");
|
||||
has_supported_output = true;
|
||||
}
|
||||
if (decode_caps.nOutputFormatMask & (1 << cudaVideoSurfaceFormat_P216)) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] - P216 (10-bit 4:2:2) supported\n");
|
||||
has_supported_output = true;
|
||||
}
|
||||
|
||||
if (!has_supported_output) {
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] FAILED: No supported output format found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -614,7 +678,8 @@ bool NVDECAV1Decoder::IsNVDECAvailable(uint32_t width, uint32_t height) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
OutputDebugStringA("[NVDECAV1Decoder::IsNVDECAvailable] SUCCESS: NVDEC AV1 is available!\n");
|
||||
sprintf_s(debug_buf, "[NVDECAV1Decoder::IsNVDECAvailable] SUCCESS: NVDEC AV1 %s is available!\n", color_space_name);
|
||||
OutputDebugStringA(debug_buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -734,7 +799,7 @@ bool NVDECAV1Decoder::CreateParser() {
|
||||
|
||||
m_parserParams.CodecType = cudaVideoCodec_AV1;
|
||||
m_parserParams.ulMaxNumDecodeSurfaces = 1; // Dummy value - will be updated by HandleVideoSequence
|
||||
m_parserParams.ulMaxDisplayDelay = 1; // CRITICAL: Required for pfnDisplayPicture to be called
|
||||
m_parserParams.ulMaxDisplayDelay = 1; // NVDEC requires >=1 for pfnDisplayPicture to be called
|
||||
m_parserParams.ulClockRate = 0; // Use default
|
||||
m_parserParams.ulErrorThreshold = 100;
|
||||
m_parserParams.pUserData = this;
|
||||
@@ -1224,7 +1289,7 @@ bool NVDECAV1Decoder::DecodeToSurface(const uint8_t* packet_data, size_t packet_
|
||||
slot_idx, my_slot.is_ready);
|
||||
OutputDebugStringA(debug_buf);
|
||||
|
||||
if (!my_slot.frame_ready.wait_for(lock, std::chrono::milliseconds(5000),
|
||||
if (!my_slot.frame_ready.wait_for(lock, std::chrono::milliseconds(10000),
|
||||
[&my_slot]() { return my_slot.is_ready; })) {
|
||||
// Timeout - decode took too long
|
||||
sprintf_s(debug_buf, "[DecodeToSurface] ERROR: Decode timeout for slot_idx=%zu (is_ready=%d)\n",
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
}
|
||||
|
||||
// NVDEC-specific methods
|
||||
bool IsNVDECAvailable(uint32_t width, uint32_t height) const;
|
||||
bool IsNVDECAvailable(uint32_t width, uint32_t height, ColorSpace color_space = ColorSpace::YUV420P) const;
|
||||
bool InitializeCUDA();
|
||||
|
||||
// Static method for availability check (used in registration)
|
||||
|
||||
@@ -654,7 +654,44 @@ bool WebMFileReader::ExtractVideoMetadata() {
|
||||
meta.frame_rate = it->frame_rate;
|
||||
meta.codec_type = it->codec_type;
|
||||
meta.codec_name = it->codec_name;
|
||||
|
||||
// Extract color space from VideoTrack Colour element
|
||||
meta.color_space = ColorSpace::YUV420P; // Default value
|
||||
const mkvparser::Tracks* tracks = m_state->segment->GetTracks();
|
||||
if (tracks) {
|
||||
const mkvparser::Track* track = tracks->GetTrackByNumber(m_state->selected_track_number);
|
||||
if (track && track->GetType() == mkvparser::Track::kVideo) {
|
||||
const mkvparser::VideoTrack* video_track = static_cast<const mkvparser::VideoTrack*>(track);
|
||||
const mkvparser::Colour* colour = video_track->GetColour();
|
||||
|
||||
if (colour) {
|
||||
// Detect color space from chroma subsampling
|
||||
// libwebm Colour reference: https://www.matroska.org/technical/elements.html
|
||||
// chroma_subsampling_horz/vert: 0=4:4:4, 1=4:2:2/4:2:0
|
||||
long long horz = colour->chroma_subsampling_horz;
|
||||
long long vert = colour->chroma_subsampling_vert;
|
||||
|
||||
if (horz == 0 && vert == 0) {
|
||||
// No subsampling = YUV444
|
||||
meta.color_space = ColorSpace::YUV444P;
|
||||
OutputDebugStringA("[WebMFileReader] Detected ColorSpace: YUV444P (4:4:4)\n");
|
||||
} else if (horz == 1 && vert == 0) {
|
||||
// Horizontal subsampling only = YUV422
|
||||
meta.color_space = ColorSpace::YUV422P;
|
||||
OutputDebugStringA("[WebMFileReader] Detected ColorSpace: YUV422P (4:2:2)\n");
|
||||
} else if (horz == 1 && vert == 1) {
|
||||
// Both horizontal and vertical subsampling = YUV420
|
||||
meta.color_space = ColorSpace::YUV420P;
|
||||
OutputDebugStringA("[WebMFileReader] Detected ColorSpace: YUV420P (4:2:0)\n");
|
||||
} else {
|
||||
// Unknown or unspecified - keep default YUV420P
|
||||
OutputDebugStringA("[WebMFileReader] Unknown chroma subsampling, using default YUV420P\n");
|
||||
}
|
||||
} else {
|
||||
OutputDebugStringA("[WebMFileReader] No Colour element found, using default YUV420P\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get duration from segment info
|
||||
const mkvparser::SegmentInfo* info = m_state->segment->GetInfo();
|
||||
@@ -674,9 +711,9 @@ bool WebMFileReader::ExtractVideoMetadata() {
|
||||
meta.file_path = m_state->file_path;
|
||||
|
||||
// Extract codec private data (AV1 sequence header) from track
|
||||
const mkvparser::Tracks* tracks = m_state->segment->GetTracks();
|
||||
if (tracks) {
|
||||
const mkvparser::Track* track = tracks->GetTrackByNumber(m_state->selected_track_number);
|
||||
const mkvparser::Tracks* tracks2 = m_state->segment->GetTracks();
|
||||
if (tracks2) {
|
||||
const mkvparser::Track* track = tracks2->GetTrackByNumber(m_state->selected_track_number);
|
||||
if (track && track->GetType() == mkvparser::Track::kVideo) {
|
||||
const mkvparser::VideoTrack* video_track = static_cast<const mkvparser::VideoTrack*>(track);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user