I'm trying to use WPF-MediaKit VideoCaptureElement to preview a web cam video, and to decode QR code if one is in a frame, therefore I need to get access to each frame recorded by web cam and according to documentation it requires EnableSampleGrabbing option on and NewVideoSample event handler.
As for now my code looks something like this.
public partial class QrScannerControl : UserControl
{
public delegate void QrResultDelegate(string qr);
public QrResultDelegate OnQrDeoded { get; set; }
private QRCodeReader _qrCodeReader = new QRCodeReader();
public QrScannerControl()
{
InitializeComponent();
VideoCapElement.EnableSampleGrabbing = true;
VideoCapElement.UseYuv = false;
VideoCapElement.NewVideoSample += (sender, args) =>
{
var binBitmap = new BinaryBitmap(new HybridBinarizer(new BitmapLuminanceSource(args.VideoFrame)));
BitMatrix bm = binBitmap.BlackMatrix;
Detector detector = new Detector(bm);
DetectorResult detectorResult = detector.detect();
var retStr = detectorResult.Points.Aggregate("Found at points ", (current, point) => current + (point.ToString() + ", "));
Console.WriteLine(retStr);
DebugLabel.Content = retStr;
var result = _qrCodeReader.decode(binBitmap);
if (result == null) return;
OnQrDeoded?.Invoke(result.Text);
};
}
}
But the event never fires.
Related
I have converted my old StartActivityForResult code to the new RegisterForActivityResult as StartActivityForResult is depreciated in the android API 29 and higher. My new code works perfectly, except that result in class ActivityResultCallback is always null. I need to be able to know when the user cancels the taking of the picture when they hit the back button, otherwise the app crashes (if a previous picture doesn't already exist) or a previously taken picture is processed again. My code (showing only the relevant code):
public class Photo : AppCompatActivity
{
public ImageView MyImageView;
public ImageButton camerabutton;
public bool PictureTaken = false;
private CurrentSubjectInfo MySubjectInfo;
private ActivityResultCallback _activityResultCallback;
private ActivityResultLauncher _activityResultLauncher;
private Uri uri;
protected override void OnCreate(Bundle bundle)
{
try
{
_activityResultCallback = new ActivityResultCallback();
_activityResultCallback.OnActivityResultCalled += ActivityResultCallback_ActivityResultCalled;
_activityResultLauncher = RegisterForActivityResult(new ActivityResultContracts.TakePicture(), _activityResultCallback);
RequestedOrientation = Android.Content.PM.ScreenOrientation.Portrait;
base.OnCreate(bundle);
SetContentView(Resource.Layout.Photo);
PictureTaken = false;
MySubjectInfo = new CurrentSubjectInfo("", "", "", "", "");
// retrieve subject information from previous activity
MySubjectInfo = Mybundle.GetParcelable("MySubjectInfo", Java.Lang.Class.FromType(typeof(CurrentSubjectInfo))) as CurrentSubjectInfo;
ImageButton camerabutton = FindViewById<ImageButton>(Resource.Id.button1);
MyImageView = FindViewById<ImageView>(Resource.Id.imageView1);
camerabutton.Click += (sender, evt) =>
{
var cameraispresent = CheckCameraHardware();
if (cameraispresent)
{
try
{
// get directory where pictures are stored
App._dir = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures);
// build file name
MySubjectInfo.Name = MySubjectInfo.Name.Replace(",", "");
MySubjectInfo.Name = MySubjectInfo.Name.Replace(" ", "");
MySubjectInfo.Name = MySubjectInfo.Name.Replace(".", "");
var filename = MySubjectInfo.Name + ".jpg";
App._file = new File(App._dir, String.Format(filename, Guid.NewGuid()));
uri = FileProvider.GetUriForFile(this, this.ApplicationContext.PackageName + ".provider",App._file);
// launch camera activity
_activityResultLauncher.Launch(uri);
}
catch (Exception e)
{
// trap error and log it
};
}
};
}
}
Boolean CheckCameraHardware()
{
Android.Content.PM.PackageManager pm = PackageManager;
if (pm.HasSystemFeature(Android.Content.PM.PackageManager.FeatureCamera))
{
// this device has a camera
return true;
}
else
{
// no camera on this device
return false;
}
}
private void ActivityResultCallback_ActivityResultCalled(object sender, ActivityResult result)
{
// result is always null, so I don't check it
try
{
// Because the resulting bitmap is rotated and too large, I set original orientation and resize
// suffice it to say it works perfectly so I won't post the code here
int height = 260;
int width = 200;
App.bitmap = App._file.Path.LoadAndResizeBitmap(width, height);
Bitmap bitmap = App.bitmap;
var filePath = App._file.AbsolutePath;
// save the resized bitmap, overwriting original file
var stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create);
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, stream);
stream.Close();
// set the imageview to the resulting bitmap
MyImageView.SetImageBitmap (App.bitmap);
// cleanup
bitmap = null;
App.bitmap = null;
PictureTaken = true;
}
catch (Exception ex)
{
PictureTaken = false;
// trap and log error
}
}
}
This is the ActivityResultCallback class:
public class ActivityResultCallback : Java.Lang.Object, IActivityResultCallback
{
public EventHandler<ActivityResult> OnActivityResultCalled;
public void OnActivityResult(Java.Lang.Object result)
{
ActivityResult activityResult = result as ActivityResult;
OnActivityResultCalled?.Invoke(this, activityResult);
}
}
As stated all this code executes perfectly with no errors except that Java.Lang.Object result is always null. I need to know when the user cancels the camera activity, I would assume that Java.Lang.Object result would indicate cancelled but I get nothing. What am I missing?
Ok, after some playing around I noticed that the parameter Java.Lang.Object result in the ActivityResultCallback class was either true or false depending on what the user did with the camera. So I changed the class to:
public class ActivityResultCallback : Java.Lang.Object, IActivityResultCallback
{
public EventHandler<ActivityResult> OnActivityResultCalled;
public void OnActivityResult(Java.Lang.Object result)
{
ActivityResult activityResult;
if ((bool)result)
{
activityResult = new ActivityResult((int)Result.Ok, null);
} else
{
activityResult = new ActivityResult((int)Result.Canceled, null);
}
OnActivityResultCalled?.Invoke(this, activityResult);
}
}
In the ActivityResultCallback_ActivityResultCalled function, I modified it to this:
private void ActivityResultCallback_ActivityResultCalled(object sender, ActivityResult result)
{
try
{
if (result.ResultCode == (int)Result.Ok)
{
int height = 260;
int width = 200;
App.bitmap = App._file.Path.LoadAndResizeBitmap(width, height);
Bitmap bitmap = App.bitmap;
var filePath = App._file.AbsolutePath;
var stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create);
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, stream);
stream.Close();
MyImageView.SetImageBitmap(App.bitmap);
bitmap = null;
App.bitmap = null;
PictureTaken = true;
}
}
catch (Exception ex)
{
// trap and log error
}
}
activityResult apparently has, at a minimum, two parameters, the result and data. I already had what I needed for data so I set that to null and cast Result.Ok or Result.Cancelled to int depending on whether result was true or false. I still don't totally understand how to use the new ActivityForResult API, but this works for me and I'm running with it.
I'm developing another sample where Messaging Center send status messages not coupled from device code to my view models.
At this point I used:
A alert message;
Label in my view;
A method by dependency injection from native code(interfaced and created before).
To notice the events before try in View models... etc
For it I used a static view instance in my share application constructor (App.xaml) where in view constructor I Subscript the status.
App (shared)
public partial class App : Application
{
public static ConnectViewModel CVM { get; set; }// Connection View Model
#region MasterDetailPage
public static MasterDetailPage MDP;
public static NavigationPage NAV = null;
public static MainView _mainpage;
#endregion
public App ()
{
InitializeComponent();
InitializeApplication();
NAV = new NavigationPage(new StarterView()) { BarBackgroundColor = Color.FromHex("701424"), BarTextColor = Color.White }; ;
MDP = new MasterDetailPage();
MDP.BackgroundColor = Xamarin.Forms.Color.FromHex("701424");
_mainpage = new MainView();
MDP.Master = _mainpage;
MDP.Detail = NAV;
MainPage = MDP;
MainPage.Title = "H2X";
}
private void InitializeApplication()
{
if (CVM == null)
{
CVM = new ConnectViewModel();
}
}
(View shared)
public MainView ()
{
InitializeComponent ();
string a="Test";
#region MessegeCenter
MessagingCenter.Subscribe<string,string>("APP", "Message_Received", async (sender,arg) =>
{
string b = a;
a = $"{arg}";
try
{
* await DisplayAlert(App.BM_Status, "Ok", "OK");*
}catch(Exception e)
{
string a = e.Message;
}
* generic_label_of_my_view = generic_label_of_my_view + "+";//It's not async one*
*string test = App.CVM.All_conn.Msg_Reciever();//Injection - It's not async one*
});
#endregion
}
Into the specific platform code (Device - UWP):
I create a timer that sends messages after some time instanced in mainpage constructor.
A HID device that notice me when some msg comes from USB.
The dispatcherTimer
void dispatcherTimer_Tick(object sender, object e)
{
DateTimeOffset time = DateTimeOffset.Now;
TimeSpan span = time - lastTime;
lastTime = time;
//Time since last tick should be very very close to Interval
TimerLog.Text += timesTicked + "\t time since last tick: " + span.ToString() + "\n";
timesTicked++;
if (timesTicked > timesToTick)
{
MessagingCenter.Send<string,string>("APP","Message_Received","MR");
}
}
The HIDInit and HID InputReport event
public async void HID_Init()
{
var selector = HidDevice.GetDeviceSelector(a_Id, b_Id, c_ID, d_ID);
var devices = await DeviceInformation.FindAllAsync(selector);
if (devices.Any())
{
// At this point the device is available to communicate with
// So we can send/receive HID reports from it generically
console_text = "HID devices found: " + devices.Count;
device = await HidDevice.FromIdAsync(devices.ElementAt(0).Id, FileAccessMode.ReadWrite);
if (device != null)
{
// At this point the device is available to communicate with
// create my input caller/event
device.InputReportReceived += inputReportReceived;//invoke caller
deviceWatcher = DeviceInformation.CreateWatcher(selector);
deviceWatcher.Removed += deviceRemovedEventHandler;//checa se nada foi removido
deviceWatcher.Start();
}
else
{
// There were no HID devices that met the selector criteria
throw new Exception("MUTT HID device not found");
}
}
else
{
// There were no HID devices that met the selector criteria
console_text = "HID device not found";
}
}
private void inputReportReceived(HidDevice sender, HidInputReportReceivedEventArgs args)
{
var bbytes = new byte[10];
wait_streaming = true;
DataReader dataReader = DataReader.FromBuffer(args.Report.Data);
dataReader.ReadBytes(bbytes);
console_text += System.Text.Encoding.ASCII.GetString(bbytes, 2, bbytes[1]);
is_read = false;
wait_streaming = false;
MessagingCenter.Send<string,string>("App","Message_Received","MR");
}
When I run any case with Dispatchertimer "works".
When I run by the Hidinputreport event with the alertmessage creates a system.exception in alertmessege line.
This is the "System.Exception"
if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
endif
When I run by the Hidinputreport event with the Label a marshalled interface crash with other thread in my call from messegingCenter in native code.
System.Exception: 'The application call a marshalled interface for another thread.
(Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))'
When I run the injection, works but I'm afraid that this Thread troubles make some semantical bug in my project cause I need to call INofifyPropertyChanged in shared code to print in my view the message but ...
Can I call it into the sender into Messeging Center Subscripte ?
How can I correct the other troubles with Threads ? Manual Reset Events ? EventWaitHandle ? (Inheritance:Object->MarshalByRefObject->WaitHandle->EventWaitHandle) ... so invasive way :/
I'm sorry if I ask some stupid question or show stupit code here ... but I don't know how to organize it WELL
Thank you in advance
Guilherme
How could i save listbox items even if i restart the app in the windows phone app. I want them to be sort of saved somehow, in a file, and then read them on the next start of the app. Please help..
Ok i am updating with a code:
public partial class MainPage : PhoneApplicationPage
{
#region VariableDeclaration
DispatcherTimer timer = new DispatcherTimer();
WebClient client = new WebClient();
WebBrowserTask Facebook = new WebBrowserTask();
WebBrowserTask YouTube = new WebBrowserTask();
WebBrowserTask Odnoklassniki = new WebBrowserTask();
WebBrowserTask Vkontakte = new WebBrowserTask();
List<ItemFormat> Items = new List<ItemFormat>();
DispatcherTimer PopulateIsoFile = new DispatcherTimer();
string SongBuffer;
int c = 1;
string Time;
#endregion
#region AppInit
// Constructor
public MainPage()
{
InitializeComponent();
if (Microsoft.Phone.Net.NetworkInformation.DeviceNetworkInformation.IsNetworkAvailable == false)
{
MessageBox.Show("No internet connection", "Error", MessageBoxButton.OKCancel);
}
else
{
if (BackgroundAudioPlayer.Instance.PlayerState == PlayState.Playing)
{
PauseBtn.Visibility = Visibility.Visible;
PlayBtn.Visibility = Visibility.Collapsed;
}
else
{
BackgroundAudioPlayer.Instance.Track = new AudioTrack(new Uri("http://air-online2.hitfm.md/hitfm.mp3"), "HITFM", "Включи себя", null, null);
PlayBtn.Visibility = Visibility.Visible;
PauseBtn.Visibility = Visibility.Collapsed;
}
BackgroundAudioPlayer.Instance.PlayStateChanged += Instance_PlayStateChanged;
SlideView.Begin();
SlideView.Completed += SlideView_Completed;
SlideView.AutoReverse = true;
}
timer.Interval = TimeSpan.FromSeconds(30);
timer.Tick += timer_Tick;
timer.Start();
Loaded += timer_Tick;
}
#region DownloadTrackInfo
void timer_Tick(object sender, EventArgs e)
{
try
{
client.Encoding = System.Text.Encoding.UTF8;
client.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.Now.ToString();
client.DownloadStringAsync(new Uri("http://air-online2.hitfm.md/status_hitfm.xsl"));
client.DownloadStringCompleted += client_DownloadStringCompleted;
}
catch (System.Net.WebException)
{
}
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
string[] raw = e.Result.Substring(166).Split('-');
if (raw[0].Contains(":"))
{
Artist.Text = raw[0].Replace(":", string.Empty).Substring(0, raw[0].Length - 1);
Title.Text = raw[1].Substring(1);
}
else
{
Artist.Text = raw[0];
Title.Text = raw[1].Substring(1);
}
TitleProgress.Visibility = Visibility.Collapsed;
Title.Foreground = new SolidColorBrush(Colors.White);
Artist.Foreground = new SolidColorBrush(Colors.White);
if (DateTime.Now.Minute < 10)
{
Time = "0" + DateTime.Now.Minute.ToString();
}
else
{
Time = DateTime.Now.Minute.ToString();
}
ItemFormat Item = new ItemFormat(e.Result.Substring(166).Replace(":", string.Empty), c, DateTime.Now.Hour.ToString() + ":" + Time);
if ((!(Item.Song == SongBuffer)) || (Recent.Items.Count == 0))
{
Recent.Items.Add(Item);
SongBuffer = Item.Song;
c += 1;
}
}
catch (System.SystemException)
{
}
}
}
public class ItemFormat
{
public string Song { get; set; }
public int Count { get; set; }
public string Time { get; set; }
public ItemFormat(string Song, int count, string time)
{
this.Song = Song;
this.Count = count;
this.Time = time;
}
}
}
I use this list box for a sort of a playlist for a radio. But i need my items to be saved even when the user clicks back button or is under lock screen. Please help me save my dear items.
There are several ways to store data between "sessions":
Using files in the IsolatedStorage to serialize to/deserialize from.
Using IsolatedStorageSettings for the same purpose, but with smaller amount of data.
Using database, either SQL CE or sqlite
I suggest that you use the first method because it is the easiest one and you will get the least errors with it. Simply serialize the data to the file whenever you need to, either on application closing or when it changes. You then load the data on startup from the file (if it exists) and fill the initial list.
I am developing a chat application using jabber-net opensource library..
my aim is to display a form (chat window ) when a message is coming.
But when I use this code, Form appears in the task bar,,, not perfectly rendered...
seems like this... More over I can see the form only when I mousehover the Icon on taskbar (Hail Windows 7)... Any form are like this...
Click here for Output Image
my code is this...
public jabber.client.JabberClient jabberClient1;
jabberClient1.User = UserName;
jabberClient1.Password = Password;
jabberClient1.Resource = resource;
jabberClient1.AutoRoster = true;
jabberClient1.OnMessage += new MessageHandler(jabberClient1_OnMessage);
private void jabberClient1_OnMessage(object sender, jabber.protocol.client.Message msg)
{
try
{
chatWindow chw = new chatWindow();
chw.Left = 0;
chw.Top = 0;
chw.TopMost = true;
//chw.LoadChat(msg.From.User, msg.From.Bare, "0");
//chw.SetMessage(msg);
chw.Show();
}
}
you have to use chw.ShowDialog()
or use if invokerequired
private delegate void dlgInvokeRequired();
public void InvokeMethode()
{
if (this.InvokeRequired == true)
{
dlgInvokeRequired d = new dlgInvokeRequired(InvokeMethode);
this.Invoke(d);
} else
{
chatWindow chw = new chatWindow();
chw.Left = 0;
chw.Top = 0;
chw.TopMost = true;
//chw.LoadChat(msg.From.User, msg.From.Bare, "0");
//chw.SetMessage(msg);
chw.Show();
}
}
I have solved it myself...
I have to use
JabberClient1.InvokeControl = FormInstance;
and, the FormInstance should be shown Before the chat window appears....
ie, It can be the contact window (Roster)....
I want my application will show on my form my class properties so I started my class with BackgroundWorker and create ProgressChanged.
my class:
public class DumpFile
{
PacketDevice _device;
public int _packetsCount;
public double _bitsPerSecond;
public double _packetsPerSecond;
public DateTime _lastTimestamp;
public delegate void dlgPackProgress(int progress);
public event dlgPackProgress evePacketProgress;
public DumpFile(PacketDevice device, string pcapPath)
{
_device = device;
_pcapPath = pcapPath;
_packetsCount = 1;
}
public void startCapturing()
{
OnPacketProgress(_packetsCount++);
using (PacketCommunicator communicator = _device.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the device
{
ThreadStart starter = delegate { openAdapterForStatistics(_device); };
new Thread(starter).Start();
using (PacketDumpFile dumpFile = communicator.OpenDump(_pcapPath)) //open the dump file
{
communicator.ReceivePackets(0, dumpFile.Dump); //start the capture
}
}
}
private void OnPacketProgress(int packet)
{
var handler = evePacketProgress;
if (handler != null)
{
handler(packet);
}
}
public void openAdapterForStatistics(PacketDevice selectedOutputDevice)
{
using (PacketCommunicator statCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the output adapter
{
ThreadStart start = delegate { test(selectedOutputDevice); };
new Thread(start).Start();
statCommunicator.SetFilter("tcp"); //compile and set the filter
statCommunicator.Mode = PacketCommunicatorMode.Statistics; //put the interface in statstics mode
statCommunicator.ReceiveStatistics(0, StatisticsHandler);
}
}
public void test(PacketDevice selectedOutputDevice)
{
using (PacketCommunicator communicator = selectedOutputDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
communicator.ReceivePackets(0, PacketHandler);
}
}
private void PacketHandler(Packet packet)
{
string result = _packetsCount.ToString() + ". " + packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + " length:" + packet.Length;
_packetsCount++;
}
private void StatisticsHandler(PacketSampleStatistics statistics)
{
DateTime currentTimestamp = statistics.Timestamp; //current sample time
DateTime previousTimestamp = _lastTimestamp; //previous sample time
_lastTimestamp = currentTimestamp; //set _lastTimestamp for the next iteration
if (previousTimestamp == DateTime.MinValue) //if there wasn't a previous sample than skip this iteration (it's the first iteration)
{
return;
}
double delayInSeconds = (currentTimestamp - previousTimestamp).TotalSeconds; //calculate the delay from the last sample
_bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
_packetsPerSecond = statistics.AcceptedPackets / delayInSeconds; //calculate packets per second
}
}
start button who start capturing:
private void btnStartCapture_Click(object sender, EventArgs e)
{
timerSniffer.Start();
btnStartTabSniffer.Enabled = false;
btnStopTabSniffer.Enabled = true;
groupBoxSelectTabSniffer.Enabled = false;
bgWorker = new BackgroundWorker();
bgWorker.WorkerReportsProgress = true;
bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWSniffer_ProgressChanged);
bgWorker.DoWork += new DoWorkEventHandler(
(s3, e3) =>
{
DumpFile dumpFile = new DumpFile(deviceForCapturing, pcapFilePathSniffer);
tshark.evePacketProgress += new DumpFile.dlgPackProgress(
(packet) =>
{
bgWorker.ReportProgress(packet, dumpFile);
});
dumpFile.startCapturing();
});
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
(s3, e3) =>
{
groupBoxSelectTabSniffer.Enabled = true;
});
bgWorker.RunWorkerAsync();
}
ProgressChanged:
private void bgWSniffer_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var dumpFile = (DumpFile)e.UserState;
lblNumberOfPacketsTabSniffer2.Text = dumpFile._packetsCount.ToString("#,##0");
lblTrafficRateTabSniffer2.Text = (dumpFile._bitsPerSecond * 0.000001).ToString("0.##") + " Mbit/sec" + " (" + dumpFile._bitsPerSecond.ToString("#,##0") + " Bits/sec" + ")";
lblPacketsRateTabSniffer2.Text = dumpFile._packetsPerSecond.ToString("#,##0") + " Packets/sec";
}
the problem is that my application "get into" ProgressChanged functions but only in one time.
I think I missed something in my class.
I can only find one call to OnPacketProgress(), and it's outside of any loop.
public void startCapturing()
{
OnPacketProgress(_packetsCount++);
....
}
So Yes, that will only be called once.
You need something inside ReceivePackets()