2025-09-21 14:52:33 +09:00
|
|
|
#include "pch.h"
|
2025-09-23 04:54:39 +09:00
|
|
|
#include "../src/Common/VideoTypes.h"
|
2025-09-22 22:01:53 +09:00
|
|
|
#include "../src/Decoder/VideoDecoderFactory.h"
|
|
|
|
|
#include "../src/FileIO/WebMFileReader.h"
|
2025-09-23 23:35:57 +09:00
|
|
|
#include <chrono>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <iomanip>
|
2025-09-21 14:52:33 +09:00
|
|
|
|
2025-09-23 04:54:39 +09:00
|
|
|
using namespace Vav2Player;
|
|
|
|
|
|
2025-09-21 14:52:33 +09:00
|
|
|
int main(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
SetConsoleCP(CP_UTF8);
|
|
|
|
|
SetConsoleOutputCP(CP_UTF8);
|
|
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
std::cout << "=== MAJOR_REFACTORING_GUIDE Phase 3: Basic Video Test ===" << std::endl;
|
2025-09-21 14:52:33 +09:00
|
|
|
|
|
|
|
|
if (argc < 2) {
|
2025-09-22 22:01:53 +09:00
|
|
|
std::cout << "Usage: " << argv[0] << " <video_file.webm>" << std::endl;
|
2025-09-21 14:52:33 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
std::string filePath = argv[1];
|
|
|
|
|
std::cout << "Testing video file: " << filePath << std::endl;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Test WebMFileReader
|
2025-09-23 04:54:39 +09:00
|
|
|
auto fileReader = std::make_unique<Vav2Player::WebMFileReader>();
|
2025-09-22 22:01:53 +09:00
|
|
|
if (!fileReader->OpenFile(filePath)) {
|
|
|
|
|
std::cout << "Failed to open video file" << std::endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2025-09-21 14:52:33 +09:00
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
auto tracks = fileReader->GetVideoTracks();
|
|
|
|
|
if (tracks.empty()) {
|
|
|
|
|
std::cout << "No video tracks found" << std::endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2025-09-21 14:52:33 +09:00
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
std::cout << "Found " << tracks.size() << " video track(s)" << std::endl;
|
2025-09-21 14:52:33 +09:00
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
// Select first track
|
|
|
|
|
if (!fileReader->SelectVideoTrack(tracks[0].track_number)) {
|
|
|
|
|
std::cout << "Failed to select video track" << std::endl;
|
|
|
|
|
return 1;
|
2025-09-21 14:52:33 +09:00
|
|
|
}
|
2025-09-22 02:15:47 +09:00
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
auto metadata = fileReader->GetVideoMetadata();
|
|
|
|
|
std::cout << "Video: " << metadata.width << "x" << metadata.height
|
|
|
|
|
<< " @ " << metadata.frame_rate << " fps" << std::endl;
|
2025-09-23 05:52:19 +09:00
|
|
|
std::cout << "Codec: " << (metadata.codec_type == VideoCodecType::AV1 ? "AV1" :
|
|
|
|
|
metadata.codec_type == VideoCodecType::VP9 ? "VP9" : "Other") << std::endl;
|
2025-09-22 02:15:47 +09:00
|
|
|
|
2025-09-24 03:33:54 +09:00
|
|
|
// Test decoder creation - Try AdaptiveNVDEC first (AUTO mode), then fallback others
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
std::cout << "=== TESTING ADAPTIVE NVDEC DECODER (AUTO MODE) ===" << std::endl;
|
|
|
|
|
auto autoDecoder = Vav2Player::VideoDecoderFactory::CreateDecoder(metadata.codec_type, Vav2Player::VideoDecoderFactory::DecoderType::AUTO);
|
|
|
|
|
bool useAuto = false;
|
|
|
|
|
if (autoDecoder && autoDecoder->Initialize(metadata)) {
|
|
|
|
|
std::cout << "[SUCCESS] AUTO decoder (AdaptiveNVDEC/fallback) initialized successfully" << std::endl;
|
|
|
|
|
std::cout << "Decoder type: " << autoDecoder->GetCodecName() << std::endl;
|
|
|
|
|
useAuto = true;
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "[FAILED] AUTO decoder failed" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 23:35:57 +09:00
|
|
|
std::cout << std::endl;
|
|
|
|
|
std::cout << "=== TESTING MEDIA FOUNDATION DECODER ===" << std::endl;
|
|
|
|
|
auto mfDecoder = Vav2Player::VideoDecoderFactory::CreateDecoder(metadata.codec_type, Vav2Player::VideoDecoderFactory::DecoderType::MEDIA_FOUNDATION);
|
|
|
|
|
bool useMF = false;
|
|
|
|
|
if (mfDecoder && mfDecoder->Initialize(metadata)) {
|
|
|
|
|
std::cout << "[SUCCESS] MediaFoundation decoder initialized successfully" << std::endl;
|
|
|
|
|
useMF = true;
|
|
|
|
|
} else {
|
2025-09-24 03:33:54 +09:00
|
|
|
std::cout << "[FAILED] MediaFoundation decoder failed" << std::endl;
|
2025-09-23 23:35:57 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
std::cout << "=== TESTING DAV1D DECODER ===" << std::endl;
|
|
|
|
|
auto dav1dDecoder = Vav2Player::VideoDecoderFactory::CreateDecoder(metadata.codec_type, Vav2Player::VideoDecoderFactory::DecoderType::DAV1D);
|
|
|
|
|
bool useDav1d = false;
|
|
|
|
|
if (dav1dDecoder && dav1dDecoder->Initialize(metadata)) {
|
|
|
|
|
std::cout << "[SUCCESS] dav1d decoder initialized successfully" << std::endl;
|
|
|
|
|
useDav1d = true;
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "[FAILED] dav1d decoder failed" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-24 03:33:54 +09:00
|
|
|
// Use the decoder that works (prefer AUTO for adaptive quality control)
|
2025-09-23 23:35:57 +09:00
|
|
|
std::unique_ptr<IVideoDecoder> decoder;
|
2025-09-24 03:33:54 +09:00
|
|
|
if (useAuto) {
|
|
|
|
|
std::cout << std::endl << "=== USING AUTO DECODER (AdaptiveNVDEC/fallback) ===" << std::endl;
|
|
|
|
|
decoder = std::move(autoDecoder);
|
|
|
|
|
} else if (useMF) {
|
2025-09-23 23:35:57 +09:00
|
|
|
std::cout << std::endl << "=== USING MEDIA FOUNDATION DECODER ===" << std::endl;
|
|
|
|
|
decoder = std::move(mfDecoder);
|
|
|
|
|
} else if (useDav1d) {
|
|
|
|
|
std::cout << std::endl << "=== USING DAV1D DECODER ===" << std::endl;
|
|
|
|
|
decoder = std::move(dav1dDecoder);
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "No working decoder found" << std::endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2025-09-22 22:01:53 +09:00
|
|
|
if (!decoder) {
|
2025-09-24 03:33:54 +09:00
|
|
|
std::string codecName = (metadata.codec_type == VideoCodecType::AV1 ? "AV1" :
|
|
|
|
|
(metadata.codec_type == VideoCodecType::VP9 ? "VP9" : "Other"));
|
|
|
|
|
std::cout << "Failed to create " << codecName << " decoder" << std::endl;
|
2025-09-22 02:15:47 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-24 03:33:54 +09:00
|
|
|
// Note: Decoder is already initialized in the selection logic above
|
|
|
|
|
std::cout << "Selected decoder is ready for use" << std::endl;
|
2025-09-22 02:15:47 +09:00
|
|
|
|
2025-09-23 23:35:57 +09:00
|
|
|
// Performance test - measure decoding performance for 4K video
|
|
|
|
|
std::cout << "=== PERFORMANCE TEST: 4K Video Decoding ===" << std::endl;
|
|
|
|
|
std::cout << "Target: 30fps (33.33ms per frame)" << std::endl;
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
|
|
int packetsRead = 0;
|
|
|
|
|
int framesDecoded = 0;
|
|
|
|
|
int maxFrames = 30; // Test 30 frames (1 second at 30fps)
|
|
|
|
|
|
|
|
|
|
auto testStartTime = std::chrono::high_resolution_clock::now();
|
|
|
|
|
double totalDecodeTime = 0.0;
|
|
|
|
|
double totalPacketReadTime = 0.0;
|
|
|
|
|
|
|
|
|
|
std::vector<double> frameDecodeTimes;
|
|
|
|
|
std::vector<double> packetReadTimes;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < maxFrames; i++) {
|
|
|
|
|
// Measure packet reading time
|
|
|
|
|
auto packetReadStart = std::chrono::high_resolution_clock::now();
|
|
|
|
|
|
2025-09-23 04:54:39 +09:00
|
|
|
Vav2Player::VideoPacket packet;
|
2025-09-22 22:01:53 +09:00
|
|
|
if (!fileReader->ReadNextPacket(packet)) {
|
2025-09-23 23:35:57 +09:00
|
|
|
std::cout << "End of file at packet " << i << std::endl;
|
2025-09-22 22:01:53 +09:00
|
|
|
break;
|
|
|
|
|
}
|
2025-09-22 02:15:47 +09:00
|
|
|
|
2025-09-23 23:35:57 +09:00
|
|
|
auto packetReadEnd = std::chrono::high_resolution_clock::now();
|
|
|
|
|
double packetReadTime = std::chrono::duration<double, std::milli>(packetReadEnd - packetReadStart).count();
|
|
|
|
|
packetReadTimes.push_back(packetReadTime);
|
|
|
|
|
totalPacketReadTime += packetReadTime;
|
|
|
|
|
packetsRead++;
|
|
|
|
|
|
|
|
|
|
// Measure frame decoding time
|
|
|
|
|
auto decodeStart = std::chrono::high_resolution_clock::now();
|
|
|
|
|
|
2025-09-23 04:54:39 +09:00
|
|
|
Vav2Player::VideoFrame frame;
|
2025-09-22 22:01:53 +09:00
|
|
|
if (decoder->DecodeFrame(packet, frame)) {
|
2025-09-23 23:35:57 +09:00
|
|
|
auto decodeEnd = std::chrono::high_resolution_clock::now();
|
|
|
|
|
double decodeTime = std::chrono::duration<double, std::milli>(decodeEnd - decodeStart).count();
|
|
|
|
|
frameDecodeTimes.push_back(decodeTime);
|
|
|
|
|
totalDecodeTime += decodeTime;
|
|
|
|
|
framesDecoded++;
|
|
|
|
|
|
|
|
|
|
std::cout << "Frame " << framesDecoded << ": "
|
|
|
|
|
<< "read=" << std::fixed << std::setprecision(2) << packetReadTime << "ms, "
|
|
|
|
|
<< "decode=" << decodeTime << "ms, "
|
|
|
|
|
<< "total=" << (packetReadTime + decodeTime) << "ms" << std::endl;
|
2025-09-22 22:01:53 +09:00
|
|
|
} else {
|
|
|
|
|
std::cout << "Frame " << i << ": decode failed" << std::endl;
|
|
|
|
|
}
|
2025-09-22 02:15:47 +09:00
|
|
|
}
|
2025-09-21 14:52:33 +09:00
|
|
|
|
2025-09-23 23:35:57 +09:00
|
|
|
auto testEndTime = std::chrono::high_resolution_clock::now();
|
|
|
|
|
double totalTestTime = std::chrono::duration<double, std::milli>(testEndTime - testStartTime).count();
|
|
|
|
|
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
std::cout << "=== PERFORMANCE RESULTS ===" << std::endl;
|
|
|
|
|
std::cout << "Frames decoded: " << framesDecoded << " / " << packetsRead << " packets" << std::endl;
|
|
|
|
|
std::cout << "Total test time: " << std::fixed << std::setprecision(2) << totalTestTime << "ms" << std::endl;
|
|
|
|
|
|
|
|
|
|
if (framesDecoded > 0) {
|
|
|
|
|
double avgDecodeTime = totalDecodeTime / framesDecoded;
|
|
|
|
|
double avgPacketReadTime = totalPacketReadTime / packetsRead;
|
|
|
|
|
double avgTotalTime = avgDecodeTime + avgPacketReadTime;
|
|
|
|
|
double achievableFPS = 1000.0 / avgTotalTime;
|
|
|
|
|
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
std::cout << "Average packet read time: " << avgPacketReadTime << "ms" << std::endl;
|
|
|
|
|
std::cout << "Average decode time: " << avgDecodeTime << "ms" << std::endl;
|
|
|
|
|
std::cout << "Average total time per frame: " << avgTotalTime << "ms" << std::endl;
|
|
|
|
|
std::cout << "Achievable FPS: " << std::fixed << std::setprecision(1) << achievableFPS << " fps" << std::endl;
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
|
|
if (achievableFPS >= 30.0) {
|
|
|
|
|
std::cout << "[SUCCESS] Can achieve 30fps target!" << std::endl;
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "[WARNING] Cannot achieve 30fps target (current: " << achievableFPS << " fps)" << std::endl;
|
|
|
|
|
|
|
|
|
|
// Identify bottleneck
|
|
|
|
|
if (avgDecodeTime > avgPacketReadTime * 2) {
|
|
|
|
|
std::cout << "[BOTTLENECK] Decoding is the main bottleneck (" << avgDecodeTime << "ms)" << std::endl;
|
|
|
|
|
} else if (avgPacketReadTime > avgDecodeTime * 2) {
|
|
|
|
|
std::cout << "[BOTTLENECK] Packet reading is the main bottleneck (" << avgPacketReadTime << "ms)" << std::endl;
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "[BOTTLENECK] Both decoding and I/O contribute to slowdown" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
std::cout << "Target frame time (30fps): 33.33ms" << std::endl;
|
|
|
|
|
std::cout << "Current frame time: " << avgTotalTime << "ms" << std::endl;
|
|
|
|
|
std::cout << "Performance gap: " << std::fixed << std::setprecision(1) << (avgTotalTime - 33.33) << "ms too slow" << std::endl;
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "[ERROR] No frames decoded successfully" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
std::cout << "=== MAJOR_REFACTORING_GUIDE Phase 3: Test completed successfully ===" << std::endl;
|
|
|
|
|
std::cout << "Basic video decoding pipeline verified!" << std::endl;
|
|
|
|
|
return 0;
|
2025-09-21 14:52:33 +09:00
|
|
|
|
2025-09-22 22:01:53 +09:00
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
std::cout << "Exception: " << e.what() << std::endl;
|
|
|
|
|
return 1;
|
|
|
|
|
} catch (...) {
|
|
|
|
|
std::cout << "Unknown exception occurred" << std::endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|