275 lines
6.6 KiB
C#
275 lines
6.6 KiB
C#
using Godot;
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace VideoOrchestra
|
|
{
|
|
/// <summary>
|
|
/// Test controller for VP9 video loading and playback
|
|
/// Demonstrates usage of VideoOrchestraManager with sample VP9 streams
|
|
/// </summary>
|
|
public partial class VP9TestController : Control
|
|
{
|
|
private VideoOrchestraManager _orchestraManager;
|
|
private TextureRect[] _textureRects;
|
|
private Label _statusLabel;
|
|
private Button _loadButton;
|
|
private Button _playButton;
|
|
private Button _stopButton;
|
|
|
|
// Test VP9 streams (would be loaded from files in real usage)
|
|
private byte[][] _testStreams;
|
|
private bool _isPlaying = false;
|
|
private int _currentFrame = 0;
|
|
|
|
public override void _Ready()
|
|
{
|
|
SetupUI();
|
|
InitializeOrchestra();
|
|
}
|
|
|
|
private void SetupUI()
|
|
{
|
|
// Get UI references
|
|
_textureRects = new TextureRect[3];
|
|
_textureRects[0] = GetNode<TextureRect>("UI/StreamContainer/Stream0/TextureRect0");
|
|
_textureRects[1] = GetNode<TextureRect>("UI/StreamContainer/Stream1/TextureRect1");
|
|
_textureRects[2] = GetNode<TextureRect>("UI/StreamContainer/Stream2/TextureRect2");
|
|
|
|
_statusLabel = GetNode<Label>("UI/StatusLabel");
|
|
_loadButton = GetNode<Button>("UI/Controls/LoadButton");
|
|
_playButton = GetNode<Button>("UI/Controls/PlayButton");
|
|
_stopButton = GetNode<Button>("UI/Controls/StopButton");
|
|
|
|
// Connect button signals
|
|
_loadButton.Pressed += OnLoadButtonPressed;
|
|
_playButton.Pressed += OnPlayButtonPressed;
|
|
_stopButton.Pressed += OnStopButtonPressed;
|
|
|
|
// Initial state
|
|
_playButton.Disabled = true;
|
|
_stopButton.Disabled = true;
|
|
|
|
UpdateStatus("Ready - Click Load to initialize VP9 streams");
|
|
}
|
|
|
|
private void InitializeOrchestra()
|
|
{
|
|
_orchestraManager = GetNode<VideoOrchestraManager>("VideoOrchestraManager");
|
|
if (_orchestraManager == null)
|
|
{
|
|
UpdateStatus("Error: VideoOrchestraManager not found!");
|
|
return;
|
|
}
|
|
|
|
// Connect signals
|
|
_orchestraManager.StreamDecoded += OnStreamDecoded;
|
|
_orchestraManager.DecoderError += OnDecoderError;
|
|
_orchestraManager.DecoderInitialized += OnDecoderInitialized;
|
|
}
|
|
|
|
private void OnDecoderInitialized(string platformName, bool hardwareEnabled)
|
|
{
|
|
var platformInfo = _orchestraManager.GetPlatformInfo();
|
|
var hardwareStatus = hardwareEnabled ? "Hardware" : "Software";
|
|
UpdateStatus($"VP9 decoder initialized on {platformName} ({hardwareStatus} decoding)");
|
|
GD.Print($"Platform capabilities: {platformInfo}");
|
|
}
|
|
|
|
private void OnLoadButtonPressed()
|
|
{
|
|
UpdateStatus("Loading VP9 test streams...");
|
|
|
|
try
|
|
{
|
|
// Load test VP9 data (in real usage, this would load from .vp9 files)
|
|
LoadTestStreams();
|
|
|
|
if (_testStreams != null && _testStreams.Length > 0)
|
|
{
|
|
_loadButton.Disabled = true;
|
|
_playButton.Disabled = false;
|
|
UpdateStatus($"Loaded {_testStreams.Length} test streams - Ready to play");
|
|
}
|
|
else
|
|
{
|
|
UpdateStatus("Error: No test streams loaded");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UpdateStatus($"Error loading streams: {ex.Message}");
|
|
GD.PrintErr($"Failed to load test streams: {ex}");
|
|
}
|
|
}
|
|
|
|
private void LoadTestStreams()
|
|
{
|
|
// Create dummy VP9 frame data for testing
|
|
// In real usage, this would read from actual .vp9 files
|
|
_testStreams = new byte[3][];
|
|
|
|
// Create test frame data (VP9 header + dummy payload)
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
_testStreams[i] = CreateDummyVP9Frame(i);
|
|
}
|
|
}
|
|
|
|
private byte[] CreateDummyVP9Frame(int streamId)
|
|
{
|
|
// Create a dummy VP9 frame for testing
|
|
// This is not a real VP9 frame - just placeholder data
|
|
var frameData = new byte[1024];
|
|
|
|
// VP9 frame header (simplified)
|
|
frameData[0] = 0x82; // VP9 signature
|
|
frameData[1] = 0x49; // VP9 signature
|
|
frameData[2] = 0x83; // VP9 signature
|
|
frameData[3] = 0x42; // VP9 signature
|
|
|
|
// Fill with test pattern based on stream ID
|
|
for (int i = 4; i < frameData.Length; i++)
|
|
{
|
|
frameData[i] = (byte)((i + streamId) % 256);
|
|
}
|
|
|
|
return frameData;
|
|
}
|
|
|
|
private void OnPlayButtonPressed()
|
|
{
|
|
if (!_isPlaying)
|
|
{
|
|
StartPlayback();
|
|
}
|
|
}
|
|
|
|
private void OnStopButtonPressed()
|
|
{
|
|
if (_isPlaying)
|
|
{
|
|
StopPlayback();
|
|
}
|
|
}
|
|
|
|
private void StartPlayback()
|
|
{
|
|
_isPlaying = true;
|
|
_playButton.Text = "Playing...";
|
|
_playButton.Disabled = true;
|
|
_stopButton.Disabled = false;
|
|
_currentFrame = 0;
|
|
|
|
UpdateStatus("Starting VP9 playback...");
|
|
|
|
// Start decoding frames
|
|
DecodeNextFrames();
|
|
}
|
|
|
|
private void StopPlayback()
|
|
{
|
|
_isPlaying = false;
|
|
_playButton.Text = "Play";
|
|
_playButton.Disabled = false;
|
|
_stopButton.Disabled = true;
|
|
|
|
UpdateStatus("Playback stopped");
|
|
}
|
|
|
|
private void DecodeNextFrames()
|
|
{
|
|
if (!_isPlaying || _testStreams == null)
|
|
return;
|
|
|
|
try
|
|
{
|
|
// Decode frames for all streams
|
|
bool anySuccess = false;
|
|
|
|
for (int streamId = 0; streamId < Math.Min(3, _testStreams.Length); streamId++)
|
|
{
|
|
bool success = _orchestraManager.DecodeFrame(_testStreams[streamId], streamId);
|
|
if (success)
|
|
{
|
|
anySuccess = true;
|
|
UpdateStreamTexture(streamId);
|
|
}
|
|
}
|
|
|
|
if (anySuccess)
|
|
{
|
|
_currentFrame++;
|
|
UpdateStatus($"Decoded frame {_currentFrame} for all streams");
|
|
|
|
// Schedule next frame (simulate 30fps)
|
|
GetTree().CreateTimer(1.0f / 30.0f).Timeout += DecodeNextFrames;
|
|
}
|
|
else
|
|
{
|
|
UpdateStatus("Error: Failed to decode frames");
|
|
StopPlayback();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UpdateStatus($"Decode error: {ex.Message}");
|
|
GD.PrintErr($"Error decoding frames: {ex}");
|
|
StopPlayback();
|
|
}
|
|
}
|
|
|
|
private void UpdateStreamTexture(int streamId)
|
|
{
|
|
if (streamId < 0 || streamId >= _textureRects.Length)
|
|
return;
|
|
|
|
try
|
|
{
|
|
var texture = _orchestraManager.GetStreamTexture(streamId);
|
|
if (texture != null)
|
|
{
|
|
_textureRects[streamId].Texture = texture;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
GD.PrintErr($"Error updating texture for stream {streamId}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void OnStreamDecoded(int streamId)
|
|
{
|
|
GD.Print($"Stream {streamId} decoded successfully");
|
|
}
|
|
|
|
private void OnDecoderError(int streamId, string error)
|
|
{
|
|
GD.PrintErr($"Decoder error for stream {streamId}: {error}");
|
|
UpdateStatus($"Error in stream {streamId}: {error}");
|
|
|
|
if (_isPlaying)
|
|
{
|
|
StopPlayback();
|
|
}
|
|
}
|
|
|
|
private void UpdateStatus(string message)
|
|
{
|
|
if (_statusLabel != null)
|
|
{
|
|
_statusLabel.Text = $"Status: {message}";
|
|
}
|
|
GD.Print($"VP9Orchestra: {message}");
|
|
}
|
|
|
|
public override void _ExitTree()
|
|
{
|
|
if (_isPlaying)
|
|
{
|
|
StopPlayback();
|
|
}
|
|
}
|
|
}
|
|
}
|