2025-09-23 05:52:19 +09:00
|
|
|
#include "pch.h"
|
|
|
|
|
#include "MockWebMFileReader.h"
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
|
|
namespace Vav2PlayerUnitTests {
|
|
|
|
|
|
|
|
|
|
MockWebMFileReader::MockWebMFileReader() {
|
|
|
|
|
CreateDefaultMockData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MockWebMFileReader::OpenFile(const std::string& file_path) {
|
|
|
|
|
m_openFileCallCount++;
|
|
|
|
|
m_lastOpenedFile = file_path;
|
|
|
|
|
|
|
|
|
|
if (!m_openFileResult) {
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::FileNotFound;
|
2025-09-23 05:52:19 +09:00
|
|
|
m_mockErrorMessage = "Mock file not found: " + file_path;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_isOpen = true;
|
|
|
|
|
m_currentFilePath = file_path;
|
|
|
|
|
m_currentFrame = 0;
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::Success;
|
2025-09-23 05:52:19 +09:00
|
|
|
m_mockErrorMessage.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MockWebMFileReader::CloseFile() {
|
|
|
|
|
m_isOpen = false;
|
|
|
|
|
m_currentFilePath.clear();
|
|
|
|
|
m_currentFrame = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MockWebMFileReader::IsFileOpen() const {
|
|
|
|
|
return m_isOpen;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 21:54:50 +09:00
|
|
|
const VavCore::VideoMetadata& MockWebMFileReader::GetVideoMetadata() const {
|
2025-09-23 05:52:19 +09:00
|
|
|
return m_mockMetadata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string MockWebMFileReader::GetFilePath() const {
|
|
|
|
|
return m_currentFilePath;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 21:54:50 +09:00
|
|
|
std::vector<VavCore::VideoTrackInfo> MockWebMFileReader::GetVideoTracks() const {
|
2025-09-23 05:52:19 +09:00
|
|
|
return m_mockTracks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MockWebMFileReader::SelectVideoTrack(uint64_t track_number) {
|
|
|
|
|
if (!m_isOpen) {
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::FileNotOpen;
|
2025-09-23 05:52:19 +09:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate track exists
|
|
|
|
|
for (const auto& track : m_mockTracks) {
|
|
|
|
|
if (track.track_number == track_number) {
|
|
|
|
|
m_selectedTrack = track_number;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::InvalidTrack;
|
2025-09-23 05:52:19 +09:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t MockWebMFileReader::GetSelectedTrackNumber() const {
|
|
|
|
|
return m_selectedTrack;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 21:54:50 +09:00
|
|
|
bool MockWebMFileReader::ReadNextPacket(VavCore::VideoPacket& packet) {
|
2025-09-23 05:52:19 +09:00
|
|
|
m_readPacketCallCount++;
|
|
|
|
|
|
|
|
|
|
if (!m_isOpen) {
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::FileNotOpen;
|
2025-09-23 05:52:19 +09:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_currentFrame >= m_endOfFileFrame || m_currentFrame >= m_mockPackets.size()) {
|
|
|
|
|
return false; // End of file
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create packet from mock data
|
|
|
|
|
const auto& mockData = m_mockPackets[m_currentFrame];
|
|
|
|
|
packet.data = std::make_unique<uint8_t[]>(mockData.size());
|
|
|
|
|
packet.size = mockData.size();
|
|
|
|
|
std::memcpy(packet.data.get(), mockData.data(), mockData.size());
|
|
|
|
|
|
|
|
|
|
packet.timestamp_seconds = static_cast<double>(m_currentFrame) / m_mockMetadata.frame_rate;
|
|
|
|
|
packet.frame_index = m_currentFrame;
|
|
|
|
|
packet.is_keyframe = (m_currentFrame % 30 == 0); // Every 30th frame is keyframe
|
|
|
|
|
|
|
|
|
|
m_currentFrame++;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MockWebMFileReader::SeekToFrame(uint64_t frame_index) {
|
|
|
|
|
if (!m_isOpen) {
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::FileNotOpen;
|
2025-09-23 05:52:19 +09:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (frame_index >= m_mockPackets.size()) {
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::SeekFailed;
|
2025-09-23 05:52:19 +09:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_currentFrame = frame_index;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MockWebMFileReader::SeekToTime(double timestamp_seconds) {
|
|
|
|
|
if (!m_isOpen) {
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::FileNotOpen;
|
2025-09-23 05:52:19 +09:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t frame_index = static_cast<uint64_t>(timestamp_seconds * m_mockMetadata.frame_rate);
|
|
|
|
|
return SeekToFrame(frame_index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t MockWebMFileReader::GetCurrentFrameIndex() const {
|
|
|
|
|
return m_currentFrame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double MockWebMFileReader::GetCurrentTimestamp() const {
|
|
|
|
|
return static_cast<double>(m_currentFrame) / m_mockMetadata.frame_rate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MockWebMFileReader::IsEndOfFile() const {
|
|
|
|
|
return m_currentFrame >= m_endOfFileFrame || m_currentFrame >= m_mockPackets.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MockWebMFileReader::Reset() {
|
|
|
|
|
if (!m_isOpen) {
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockError = VavCore::WebMErrorCode::FileNotOpen;
|
2025-09-23 05:52:19 +09:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_currentFrame = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t MockWebMFileReader::GetTotalFrames() const {
|
|
|
|
|
return m_mockPackets.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double MockWebMFileReader::GetDuration() const {
|
|
|
|
|
return m_mockMetadata.duration_seconds;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 21:54:50 +09:00
|
|
|
VavCore::WebMErrorCode MockWebMFileReader::GetLastError() const {
|
2025-09-23 05:52:19 +09:00
|
|
|
return m_mockError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string MockWebMFileReader::GetLastErrorString() const {
|
|
|
|
|
return m_mockErrorMessage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mock control methods
|
2025-09-25 21:54:50 +09:00
|
|
|
void MockWebMFileReader::SetMockVideoMetadata(const VavCore::VideoMetadata& metadata) {
|
2025-09-23 05:52:19 +09:00
|
|
|
m_mockMetadata = metadata;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 21:54:50 +09:00
|
|
|
void MockWebMFileReader::SetMockVideoTracks(const std::vector<VavCore::VideoTrackInfo>& tracks) {
|
2025-09-23 05:52:19 +09:00
|
|
|
m_mockTracks = tracks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MockWebMFileReader::SetMockPackets(const std::vector<std::vector<uint8_t>>& packets) {
|
|
|
|
|
m_mockPackets = packets;
|
|
|
|
|
// Update metadata to match packet count
|
|
|
|
|
m_mockMetadata.total_frames = packets.size();
|
|
|
|
|
m_mockMetadata.duration_seconds = static_cast<double>(packets.size()) / m_mockMetadata.frame_rate;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 21:54:50 +09:00
|
|
|
void MockWebMFileReader::SetMockError(VavCore::WebMErrorCode error, const std::string& message) {
|
2025-09-23 05:52:19 +09:00
|
|
|
m_mockError = error;
|
|
|
|
|
m_mockErrorMessage = message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MockWebMFileReader::SetOpenFileResult(bool success) {
|
|
|
|
|
m_openFileResult = success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MockWebMFileReader::SetEndOfFileAtFrame(uint64_t frame_index) {
|
|
|
|
|
m_endOfFileFrame = frame_index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Private helper methods
|
|
|
|
|
void MockWebMFileReader::CreateDefaultMockData() {
|
|
|
|
|
// Default metadata for 1920x1080 30fps AV1 video
|
|
|
|
|
m_mockMetadata.width = 1920;
|
|
|
|
|
m_mockMetadata.height = 1080;
|
|
|
|
|
m_mockMetadata.frame_rate = 30.0;
|
2025-09-25 21:54:50 +09:00
|
|
|
m_mockMetadata.codec_type = VavCore::VideoCodecType::AV1;
|
|
|
|
|
m_mockMetadata.color_space = VavCore::ColorSpace::BT709;
|
2025-09-23 05:52:19 +09:00
|
|
|
m_mockMetadata.total_frames = 100; // 100 frames = ~3.33 seconds
|
|
|
|
|
m_mockMetadata.duration_seconds = 100.0 / 30.0;
|
|
|
|
|
|
|
|
|
|
// Default video track
|
2025-09-25 21:54:50 +09:00
|
|
|
VavCore::VideoTrackInfo track;
|
2025-09-23 05:52:19 +09:00
|
|
|
track.track_number = 1;
|
|
|
|
|
track.codec_id = "V_AV01";
|
|
|
|
|
track.codec_name = "AV1";
|
2025-09-25 21:54:50 +09:00
|
|
|
track.codec_type = VavCore::VideoCodecType::AV1;
|
2025-09-23 05:52:19 +09:00
|
|
|
track.width = 1920;
|
|
|
|
|
track.height = 1080;
|
|
|
|
|
track.frame_rate = 30.0;
|
|
|
|
|
track.is_enabled = true;
|
|
|
|
|
m_mockTracks.push_back(track);
|
|
|
|
|
|
|
|
|
|
// Create 100 mock AV1 packets
|
|
|
|
|
m_mockPackets.clear();
|
|
|
|
|
for (uint64_t i = 0; i < 100; ++i) {
|
|
|
|
|
m_mockPackets.push_back(CreateMockAV1Packet(i));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_selectedTrack = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<uint8_t> MockWebMFileReader::CreateMockAV1Packet(uint64_t frame_index) {
|
|
|
|
|
// Create a minimal mock AV1 packet
|
|
|
|
|
// Real AV1 packets are complex, but for testing we just need valid data
|
|
|
|
|
std::vector<uint8_t> packet;
|
|
|
|
|
|
|
|
|
|
// AV1 OBU header pattern (simplified)
|
|
|
|
|
packet.push_back(0x0A); // OBU type (frame)
|
|
|
|
|
packet.push_back(0x00); // OBU extension flag
|
|
|
|
|
|
|
|
|
|
// Mock frame size (varies by frame index for realism)
|
|
|
|
|
uint32_t frame_size = 1000 + (frame_index % 500); // 1000-1500 bytes
|
|
|
|
|
|
|
|
|
|
// Add frame size in LEB128 format (simplified)
|
|
|
|
|
packet.push_back(static_cast<uint8_t>(frame_size & 0x7F));
|
|
|
|
|
packet.push_back(static_cast<uint8_t>((frame_size >> 7) & 0x7F));
|
|
|
|
|
|
|
|
|
|
// Fill with mock data
|
|
|
|
|
for (uint32_t i = 0; i < frame_size; ++i) {
|
|
|
|
|
packet.push_back(static_cast<uint8_t>((frame_index + i) & 0xFF));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return packet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Vav2PlayerUnitTests
|