Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use TextureView instead of SurfaceView on Android. #459

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 17 additions & 3 deletions Samples/Forms/Core/CustomScanPage.cs
Expand Up @@ -21,17 +21,27 @@ public CustomScanPage () : base ()
VerticalOptions = LayoutOptions.FillAndExpand,
AutomationId = "zxingScannerView",
};

var formats = zxing.Options.PossibleFormats;
formats.Clear();
formats.Add(ZXing.BarcodeFormat.CODE_128);
formats.Add(ZXing.BarcodeFormat.CODE_39);
formats.Add(ZXing.BarcodeFormat.QR_CODE);

zxing.Options.DelayBetweenContinuousScans = 1000;

zxing.IsTorchOn = true;

zxing.OnScanResult += (result) =>
Device.BeginInvokeOnMainThread (async () => {

// Stop analysis until we navigate away so we don't keep reading barcodes
zxing.IsAnalyzing = false;
zxing.IsAnalyzing = true;

// Show an alert
await DisplayAlert ("Scanned Barcode", result.Text, "OK");

// Navigate away
await Navigation.PopAsync ();
zxing.IsAnalyzing = true;
});

overlay = new ZXingDefaultOverlay
Expand All @@ -46,6 +56,10 @@ public CustomScanPage () : base ()
};
var grid = new Grid
{
RowDefinitions = {
new RowDefinition { Height = new GridLength(1, GridUnitType.Star) },
new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }
},
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
Expand Down
3 changes: 3 additions & 0 deletions Samples/Forms/Droid/FormsSample.Droid.csproj
Expand Up @@ -16,6 +16,7 @@
<AssemblyName>FormsSample.Droid</AssemblyName>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
Expand All @@ -29,6 +30,7 @@
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
<ConsolePause>false</ConsolePause>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
Expand All @@ -39,6 +41,7 @@
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<ConsolePause>false</ConsolePause>
<AndroidSupportedAbis>armeabi;armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="FormsViewGroup, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
Expand Down
8 changes: 0 additions & 8 deletions Samples/Forms/iOS/FormsSample.iOS.csproj
Expand Up @@ -23,8 +23,6 @@
<ConsolePause>false</ConsolePause>
<MtouchArch>i386</MtouchArch>
<MtouchLink>None</MtouchLink>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<MtouchUseSGen>true</MtouchUseSGen>
<MtouchFastDev>true</MtouchFastDev>
<MtouchDebug>true</MtouchDebug>
<CodesignKey>iPhone Developer</CodesignKey>
Expand All @@ -40,9 +38,7 @@
<MtouchArch>ARMv7, ARM64</MtouchArch>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchFloat32>true</MtouchFloat32>
<MtouchUseSGen>true</MtouchUseSGen>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType>full</DebugType>
Expand All @@ -53,9 +49,7 @@
<ConsolePause>false</ConsolePause>
<MtouchArch>i386</MtouchArch>
<MtouchLink>None</MtouchLink>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchUseSGen>true</MtouchUseSGen>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>true</DebugSymbols>
Expand All @@ -72,8 +66,6 @@
<CodesignKey>iPhone Developer</CodesignKey>
<DeviceSpecificBuild>true</DeviceSpecificBuild>
<MtouchDebug>true</MtouchDebug>
<MtouchUseSGen>true</MtouchUseSGen>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<MtouchProfiling>true</MtouchProfiling>
</PropertyGroup>
<ItemGroup>
Expand Down
114 changes: 32 additions & 82 deletions Source/ZXing.Net.Mobile.Android/CameraAccess/CameraAnalyzer.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Android.Views;
using ApxLabs.FastAndroidCamera;

namespace ZXing.Mobile.CameraAccess
Expand All @@ -10,18 +9,16 @@ public class CameraAnalyzer
{
private readonly CameraController _cameraController;
private readonly MobileBarcodeScanningOptions _scanningOptions;
private readonly CameraEventsListener _cameraEventListener;
private Task _processingTask;
private DateTime _lastPreviewAnalysis = DateTime.UtcNow;
private bool _wasScanned;
private BarcodeReaderGeneric<FastJavaByteArrayYUVLuminanceSource> _barcodeReader;

public CameraAnalyzer(SurfaceView surfaceView, MobileBarcodeScanningOptions scanningOptions)
public CameraAnalyzer(CameraController cameraController, MobileBarcodeScanningOptions scanningOptions)
{
_scanningOptions = scanningOptions;
_cameraEventListener = new CameraEventsListener();
_cameraController = new CameraController(surfaceView, _cameraEventListener, scanningOptions);
Torch = new Torch(_cameraController, surfaceView.Context);
_cameraController = cameraController;

Torch = new Torch(_cameraController);
}

public event EventHandler<Result> BarcodeFound;
Expand All @@ -43,13 +40,13 @@ public void ResumeAnalysis()
public void ShutdownCamera()
{
IsAnalyzing = false;
_cameraEventListener.OnPreviewFrameReady -= HandleOnPreviewFrameReady;
_cameraController.OnPreviewFrameReady -= HandleOnPreviewFrameReady;
_cameraController.ShutdownCamera();
}

public void SetupCamera()
{
_cameraEventListener.OnPreviewFrameReady += HandleOnPreviewFrameReady;
_cameraController.OnPreviewFrameReady += HandleOnPreviewFrameReady;
_cameraController.SetupCamera();
}

Expand All @@ -75,11 +72,6 @@ private bool CanAnalyzeFrame
if (!IsAnalyzing)
return false;

//Check and see if we're still processing a previous frame
// todo: check if we can run as many as possible or mby run two analyzers at once (Vision + ZXing)
if (_processingTask != null && !_processingTask.IsCompleted)
return false;

var elapsedTimeMs = (DateTime.UtcNow - _lastPreviewAnalysis).TotalMilliseconds;
if (elapsedTimeMs < _scanningOptions.DelayBetweenAnalyzingFrames)
return false;
Expand All @@ -100,24 +92,17 @@ private void HandleOnPreviewFrameReady(object sender, FastJavaByteArray fastArra
_wasScanned = false;
_lastPreviewAnalysis = DateTime.UtcNow;

_processingTask = Task.Run(() =>
{
try
{
DecodeFrame(fastArray);
} catch (Exception ex) {
Console.WriteLine(ex);
}
}).ContinueWith(task =>
try
{
DecodeFrame(fastArray);
}
catch (Exception ex)
{
if (task.IsFaulted)
Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "DecodeFrame exception occurs");
}, TaskContinuationOptions.OnlyOnFaulted);
Android.Util.Log.Debug(MobileBarcodeScanner.TAG, $"DecodeFrame exception occured: {ex.Message}");
}
}

byte[] _matrix;
byte[] _rotatedMatrix;

private byte[] buffer;
private void DecodeFrame(FastJavaByteArray fastArray)
{
var cameraParameters = _cameraController.Camera.GetParameters();
Expand All @@ -126,52 +111,36 @@ private void DecodeFrame(FastJavaByteArray fastArray)

InitBarcodeReaderIfNeeded();

var rotate = false;
var newWidth = width;
var newHeight = height;

// use last value for performance gain
var cDegrees = _cameraController.LastCameraDisplayOrientationDegree;
var rotate = (cDegrees == 90 || cDegrees == 270);

if (cDegrees == 90 || cDegrees == 270)
{
rotate = true;
newWidth = height;
newHeight = width;
}

ZXing.Result result = null;
Result result = null;
var start = PerformanceCounter.Start();

LuminanceSource luminanceSource;

var fast = new FastJavaByteArrayYUVLuminanceSource(fastArray, width, height, 0, 0, width, height); // _area.Left, _area.Top, _area.Width, _area.Height);
if (rotate)
if (rotate)
{
fast.CopyMatrix(ref _matrix);
RotateCounterClockwise(_matrix, ref _rotatedMatrix, width, height); // _area.Width, _area.Height);
luminanceSource = new PlanarYUVLuminanceSource(_rotatedMatrix, height, width, 0, 0, height, width, false); // _area.Height, _area.Width, 0, 0, _area.Height, _area.Width, false);
fastArray.Transpose(ref buffer, width, height);
var tmp = width;
width = height;
height = tmp;
}
else
luminanceSource = fast;
var luminanceSource = new FastJavaByteArrayYUVLuminanceSource(fastArray, width, height, 0, 0, width, height); // _area.Left, _area.Top, _area.Width, _area.Height);

result = _barcodeReader.Decode(luminanceSource);

fastArray.Dispose();
fastArray = null;
PerformanceCounter.Stop(start, "Decode Time: {0} ms (width: " + width + ", height: " + height + ", degrees: " + cDegrees + ", rotate: " + rotate + ")");

PerformanceCounter.Stop(start,
"Decode Time: {0} ms (width: " + width + ", height: " + height + ", degrees: " + cDegrees + ", rotate: " +
rotate + ")");

if (result != null)
{
Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "Barcode Found: " + result.Text);
if (result != null)
{
Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "Barcode Found: " + result.Text);

_wasScanned = true;
BarcodeFound?.Invoke(this, result);
return;
}
_wasScanned = true;
BarcodeFound?.Invoke(this, result);
}
else
AutoFocus();
}

private void InitBarcodeReaderIfNeeded()
Expand Down Expand Up @@ -200,24 +169,5 @@ private void InitBarcodeReaderIfNeeded()
_barcodeReader.Options.PossibleFormats.Add(pf);
}
}

private static byte[] RotateCounterClockwise(byte[] data, int width, int height)
{
var rotatedData = new byte[data.Length];
for (var y = 0; y < height; y++)
for (var x = 0; x < width; x++)
rotatedData[x*height + height - y - 1] = data[x + y*width];
return rotatedData;
}

private void RotateCounterClockwise(byte[] source, ref byte[] target, int width, int height)
{
if (source.Length != (target?.Length ?? -1))
target = new byte[source.Length];

for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
target[x * height + height - y - 1] = source[x + y * width];
}
}
}