Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
docfx_project/log.txt
log.txt

src/Native/* linguist-vendored

# Build results
[Dd]ebug/
[Dd]ebugPublic/
Expand Down
13 changes: 3 additions & 10 deletions src/Maui/Addons/DrawnUi.Maui.Camera/Apple/SkiaCamera.Apple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,16 +308,9 @@ private async Task CaptureFrameCore()
}
}

if (imageToDraw == null)
{
var raw = nativeCam.GetRawFullImage();
if (raw.Image != null)
{
imageToDraw = raw.Image;
imageRotation = raw.Rotation;
imageFlip = raw.Flip;
}
}
// No fallback to GetRawFullImage - it reads _latestRecordingFrame which was
// populated earlier and can be older than what zero-copy previously encoded,
// causing out-of-order frames in the video. Better to drop a frame than glitch.
}

// Fallback to standard preview image (slower, already rotated)
Expand Down
42 changes: 29 additions & 13 deletions src/Maui/Samples/Camera/CameraTestPage.AppCamera.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,55 @@ public partial class CameraTestPage
public class AppCamera : SkiaCamera
{
// Audio visualizer (switch between AudioOscillograph and AudioLevels)
private IAudioVisualizer _audioVisualizer = new AudioLevelsVU();
private IAudioVisualizer _audioVisualizer = null;
private int _visualizerIndex = 0;

public static readonly BindableProperty VisualizerNameProperty = BindableProperty.Create(
nameof(VisualizerName),
typeof(string),
typeof(AppCamera),
"VU Meter");
"None");

public string VisualizerName
{
get => (string)GetValue(VisualizerNameProperty);
set => SetValue(VisualizerNameProperty, value);
}

public void SwitchVisualizer()
public void SwitchVisualizer(int index = -1)
{
_visualizerIndex++;
if (_visualizerIndex > 6) _visualizerIndex = 0;
if (index >= 0)
{
_visualizerIndex = index;
}
else
{
_visualizerIndex++;
}
if (_visualizerIndex > 8) _visualizerIndex = 0;

var old = _audioVisualizer;
bool useGain = true;
bool useGain = true;

switch (_visualizerIndex)
Comment on lines 36 to 40
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SwitchVisualizer can set _visualizerIndex to 7 (it increments through 0..8) but the switch has no case 7 and no default. In that situation _audioVisualizer remains pointing to the old instance, but old is still disposed at the end of the method, leaving _audioVisualizer referencing a disposed object (subsequent AddSample/Render calls may fail or behave incorrectly). Add a case 7 (or change the wrap limit) and/or add a default that assigns a new visualizer/null before disposing the old one.

Copilot uses AI. Check for mistakes.
{
case 0:
_audioVisualizer = new AudioSoundBars();
useGain = true;
VisualizerName = "Sound Bars";
break;
case 1:
_audioVisualizer = new AudioLevelsVU();
VisualizerName = "VU Meter";
break;
case 1:
case 2:
_audioVisualizer = new AudioLevelsPeak();
VisualizerName = "Peak Monitor";
break;
case 2:
_audioVisualizer = new AudioLevels();
VisualizerName = "Spectrum";
break;
//case 2:
// _audioVisualizer = new AudioLevels();
// VisualizerName = "Spectrum";
// break;
case 3:
_audioVisualizer = new AudioOscillograph();
useGain = true;
Expand All @@ -59,6 +71,10 @@ public void SwitchVisualizer()
VisualizerName = "Tuner";
break;
case 6:
_audioVisualizer = new AudioWaveformBars();
VisualizerName = "Waveform Bars";
break;
case 8:
_audioVisualizer = null;
VisualizerName = "None";
break;
Expand Down Expand Up @@ -89,7 +105,7 @@ public override void OnWillDisposeWithChildren()
_paintRec = null;
_paintPreview?.Dispose();
_paintPreview = null;

(_audioVisualizer as IDisposable)?.Dispose();
_audioVisualizer = null;
}
Expand Down Expand Up @@ -158,6 +174,6 @@ public void DrawOverlay(DrawableFrame frame)
private SKPaint _paintRec;
}


}
}
10 changes: 7 additions & 3 deletions src/Maui/Samples/Camera/CameraTestPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,14 +263,18 @@ private void CreateContent()
CornerRadius = 8,
UseCache = SkiaCacheType.Image
}
.OnTapped(me => { CameraControl.SwitchVisualizer(); })
.OnTapped(me =>
{
CameraControl.SwitchVisualizer();
})
.ObserveProperty(CameraControl, nameof(CameraControl.VisualizerName), me =>
{
me.Text = $"Vis: {CameraControl.VisualizerName}";
me.Text = $"{CameraControl.VisualizerName}";
})
.ObserveProperty(CameraControl, nameof(CameraControl.CaptureMode), me =>
{
me.IsVisible = CameraControl.CaptureMode == CaptureModeType.Video;
CameraControl.SwitchVisualizer(0);
//me.IsVisible = CameraControl.CaptureMode == CaptureModeType.Video;
}),
Comment on lines 274 to 278
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This CaptureMode observer now contains a commented-out visibility assignment and does not otherwise use the me parameter, which leaves dead code and an unused lambda parameter. Either restore the visibility logic, remove the observer entirely, or change the lambda parameter to _ and delete the commented line to keep the UI code clean.

Copilot uses AI. Check for mistakes.

// Take Picture button (only visible in Still mode)
Expand Down
Loading
Loading