My windows phone app needs to record a video from front-camera and send it to the server through a webservice.
Here while I'm trying to record video from front-camera, I'm getting mirror inverted video. Means front-camera records 180 degree rotated video.
what i think probably the only solution of it is to rotate the recorded video stream to 180 degree back.
Question:
is there any other solution to record proper video by front-camera in wp8?
if not, how to rotate the video stream 180 degree? any c# API to do it..?
Edit:
Here is code that I'm using:
XAML code for VideoBrush
<Canvas x:Name="CanvasLayoutRoot" RenderTransformOrigin="0.5 0.5"
Width="{Binding ActualHeight, ElementName=LayoutRoot}"
Height="{Binding ActualWidth, ElementName=LayoutRoot}"
Margin="-160 0 0 0">
<!--Background="Transparent"-->
<Canvas.Background>
<VideoBrush x:Name="videoBrush" />
</Canvas.Background>
<Canvas.RenderTransform>
<RotateTransform x:Name="rt" />
</Canvas.RenderTransform>
</Canvas>
Initializing camera
public async void InitializeVideoRecorder()
{
try
{
if (videoCapture == null)
{
// below line of code will detect if "Front Camera" is available or not
// if availble, then open it or it will open "Back Camera"
videoCapture = await AudioVideoCaptureDevice.OpenAsync(
AudioVideoCaptureDevice.AvailableSensorLocations.Contains(CameraSensorLocation.Front) ? CameraSensorLocation.Front : CameraSensorLocation.Back,
new Windows.Foundation.Size(640, 480));
videoCapture.RecordingFailed += videoCapture_RecordingFailed;
videoCapture.SetProperty(KnownCameraGeneralProperties.EncodeWithOrientation, videoCapture.SensorRotationInDegrees);
// Initialize the camera if it exists on the phone.
if (videoCapture != null)
{
videoBrush.SetSource(videoCapture);
if (!AudioVideoCaptureDevice.AvailableSensorLocations.Contains(CameraSensorLocation.Front))
{
rt.Angle = videoCapture.SensorRotationInDegrees;
}
else
{
rt.Angle = -(videoCapture.SensorRotationInDegrees);
}
}
else
{
MessageBox.Show("Unable to load Camera. Please try again later.", App.appName, MessageBoxButton.OK);
NavigationService.GoBack();
}
}
}
catch (Exception ex)
{
(new WebServices()).catchExceptions(ex);
NavigationService.GoBack();
}
}
Starting VideoCapture
private async Task StartVideoRecording()
{
try
{
// Gets the application data folder
StorageFolder applicationFolder = ApplicationData.Current.LocalFolder;
StorageFolder transfersFolder = await (await applicationFolder.GetFolderAsync("Shared")).GetFolderAsync("Transfers");
// Create the file specified in the application data folder
videoFileName = selectedQue.response.template_id + "_" + selectedQue.response.id + "_" + selectedQue.response.invite_id +".mp4";
StorageFile storageFile = await transfersFolder.CreateFileAsync(videoFileName, CreationCollisionOption.ReplaceExisting);
// Open a file stream, ready to write video data
randomAccessStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite);
// Video recording to the specified stream
await videoCapture.StartRecordingToStreamAsync(randomAccessStream);
isRecordingStarted = true;
//timer = "0:00";
tbTimer.Text = "0:00";
dt.Start();
}
catch (Exception ex)
{
(new WebServices()).catchExceptions(ex);
}
}
This worked for me in the past, it was just a barcode scanner app that I coded up to fulfill a functional requirement. I put the transform on the <VideoBrush>.
<Grid x:Name="ContentPanel" Margin="12,0,12,0">
<Canvas x:Name="cam_canvas" Width="480" Height="480">
<Canvas.Background>
<VideoBrush x:Name="cam_video_brush" Stretch="None">
<VideoBrush.RelativeTransform>
<CompositeTransform Rotation="90" CenterX="0.5" CenterY="0.5" />
</VideoBrush.RelativeTransform>
</VideoBrush>
</Canvas.Background>
</Canvas>
</Grid>
Finally i solved my problem after 24 hours of efforts with below solution.
The line of code that causing issue by rotating video was below.
videoCapture.SetProperty(KnownCameraGeneralProperties.EncodeWithOrientation, videoCapture.SensorRotationInDegrees);
here videoCapture is object of AudioVideoCaptureDevice
While using front camera, we need to invert the rotation of cameraSensor.
So I've used the above same code (mentioned in question) with one tiny modification in this videoCapture.SetProperty line of code. the correct line of code is as below.
videoCapture.SetProperty(KnownCameraGeneralProperties.EncodeWithOrientation, -(videoCapture.SensorRotationInDegrees));
I just inverted the videoCapture.SensorRotationInDegrees by adding one minus sign (-) before it.
Hope this helps all..
Related
I have following code for capture element in my xaml.
<CaptureElement Width="400" Height="400" x:Name="cameraCapture" Stretch="UniformToFill" Margin="0,0,0,40">
</CaptureElement>
My page loaded
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
await captureManager.InitializeAsync();
cameraCapture.Source = captureManager;
await captureManager.StartPreviewAsync();
}
in preview it shows rotated image
if I set rotation to preview than in view it works fine but saved image is still rotated to 90 degree. How can I fix this?
captureManager.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
After you call CapturePhotoToStreamAsync you should apply these things on the stream:
//create decoder and encoder
BitmapDecoder dec = await BitmapDecoder.CreateAsync(imageStream);
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(imageStream, dec);
//roate the image
enc.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;
//write changes to the image stream
await enc.FlushAsync();
It's just a snippet, but I guess you get the idea.
For full code sample take a look here: https://dzone.com/articles/how-capture-photo-your-windows-0
I am unable to receive raw notification on my WindowsPhone8.
Followed :https://github.com/barryvdh/PushPlugin/#uccb-wp8-only
Able to get toast notification. In my app toggle is happening like below.
Case 1: If I comment ecb able to get both raw and toast but not
channel uri.
Case 2: If I won't comment ecb able to get toast and channel uri but
not raw
My code as follows:
if (device.platform == "Win32NT") {
console.log("called");
pushNotification.register(
channelHandler,
errorHandler,
{
"channelName": "channelName",
"ecb": onNotificationWP8,
"uccb": channelHandler,
"errcb": jsonErrorHandler
});
}
else {
console.log("not called");
}
}
function channelHandler(event) {
var uri = event.uri;
console.log("UUUUURRRRRRRRRRRIIIIIIIII :" + uri);
}
function errorHandler(e) {
}
function jsonErrorHandler(error) {
$("#app-status-ul").append('<li style="color:red;">error:' + error.code + '</li>');
$("#app-status-ul").append('<li style="color:red;">error:' + error.message + '</li>');
}
function onNotificationWP8(e) {
console.log("notification called");
if (e.type == "toast" && e.jsonContent){
pushNotification.showToastNotification(successHandler, errorHandler,
{
"Title": e.jsonContent["wp:Text1"], "Subtitle": e.jsonContent["wp:Text2"], "NavigationUri": e.jsonContent["wp:Param"]
});
}
if (e.type == "raw" && e.jsonContent) {
alert(e.jsonContent.Body);
}
}
Tried with error and trail methods. Please suggest what might went wrong.
The issue observed does not appear to be related to Worklight at all. From the description and the code snippet, you are bypassing Worklight client SDK and server completely , and using a custom Cordova Push plugin. The custom plugin's working in your application should be analyzed to understand the variance in behaviour.
Since you are not using Worklight Push at all, you can try disabling it and check if this helps your case.
To do this, navigate to the config.xml . This will be located in apps/YourAppName/WindowsPhone8/native/Resources folder.
Look for :
<feature name="Push">
<param name="wp-package" value="Push" />
</feature>
Change this to:
<feature name="Push">
<param name="wp-package" value="Push" />
<param name="onload" value="false" />
</feature>
On the query regarding Worklight API:
There are no Worklight APIs that return Channel URI. When using Worklight SDK for Push, all this is done automatically and hidden from the user. Even with a Push Adapter in place, it is not possible to obtain the channel URI as there no APIs published to obtain this information.
Finally it got solved by adding Coding4Fun.Toolkit.Controls.dll
And some code updation in PushPlugin.cs
using Coding4Fun.Toolkit.Controls;
using System.Windows.Threading;
void PushChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
string msg = string.Empty;
foreach (var item in e.Collection)
{
if (item.Key == "wp:Text1")
{
msg = item.Value;
}
}
MessageBox.Show(msg, "Notification", MessageBoxButton.OK);
});
}
My heart-full thanks to Rajith who helped me to make it happen.
I know that now in Windows Phone 8.1 and Windows 8.1, it's easy to choose multi-photos using FileOpenPicker.
But in Windows Phone 8.0, only native code have access to the API, so if we have to choose multi-photos to do something(that is ,like uploading), we have to implemenet it by toolkit:LongListMultiSelector .
By doing this, I have a performance problem.
Here is the XAML:
<ScrollViewer x:Name="ScrowllViewAlbum" HorizontalAlignment="Left" Height="500" VerticalAlignment="Top" Width="458" >
<toolkit:LongListMultiSelector
x:Name="AlbumList"
IsGroupingEnabled="False"
GridCellSize="100,100"
LayoutMode="Grid"
HideEmptyGroups="True"
IsSelectionEnabled="False"
EnforceIsSelectionEnabled="False"
CacheMode="BitmapCache"
ItemsSource="{Binding}"
Width="459"
ItemTemplate="{StaticResource AllPhotoTemplete}" Background="Black"
/>
</ScrollViewer>
and in ViewModel:
public void LoadAllPhotos()
{
Allphotos = new ObservableCollection<BitmapImage>();
MediaLibrary medialib = new MediaLibrary();
PictureCollection pics = medialib.Pictures;
if (pics.Count!=0)
{
BitmapImage image = new BitmapImage();
foreach(var pic in pics)
{
Stream stream = pic.GetImage();
image.SetSource(stream);
Allphotos.Add(image);
}
}
}
However, during the debug, it throw out an exception of no insufficient memory.
Can you give me some idea to optimize the function?
Thanks :-)
There is no other way then implement the picker yourself.
since you are only loading the images for a preview, only load the thumbnail like:
var image = new BitmapImage();
image.SetSource(pic.GetThumbnail());
I am trying to make an application that gets the streaming video data using JavaCV and send it to Web socket server. Then, the Web socket server distributes the video data to connected client(s).
1. Application gets live streaming data(MP4) from my PC's webcam using JavaCV.
2. Application keeps sending it to web socket server.
3. The server gets it as binary and send it to connected client.
4. Web browser connects to the server and Javascript running on browser shows the live video after receiving it from server.
I am new to JavaCV and OpenCV. The snippet below works for drawing video using com.googlecode.javacv.CanvasFrame with no problem. However, I am not sure how to grab MP4 data as live streaming data.
try {
FrameGrabber grabber = FrameGrabber.createDefault(0);
grabber.setFormat("mp4");;
grabber.setFrameRate(30);
grabber.setImageWidth(640);
grabber.setImageHeight(480);
grabber.start();
double frameRate = grabber.getFrameRate();
long wait = (long) (1000 / (frameRate == 0 ? 10 : frameRate));
ByteBuffer buf = null;
while (true) {
Thread.sleep(wait);
IplImage image = grabber.grab();
if(image != null) {
buf = image.getByteBuffer();
send(buf); // Send video data using web socket.
}
}
} catch (FrameGrabber.Exception ex) {
Logger.getLogger(WSockClient.class.getName()).log(Level.SEVERE, null, ex);
}
The below are the code for web socket server and Javascript/HTML5 client.
The both code works fine if the application reads MP4 file from local disk, and send it to the server. But the data using JavaCV like above seems to be invalid for showing on browser.
The server just receives the data and distribute it to the clients. I believe there seems to have no problem. Here is the code.
#OnMessage
public void binaryMessage(ByteBuffer buf, Session client) throws IOException, EncodeException {
for (Session otherSession : peers) {
if (!otherSession.equals(client)) {
otherSession.getAsyncRemote().sendBinary(buf, new StreamHandler());
}
}
}
Here is the Javascript/HTML5.
<body>
<video controls width="640" height="480" autoplay></video><br>
<canvas id="canvas1" width="640" height="480"></canvas><br>
</body>
<script>
var ws;
var protocol = 'ws';
var host = "localhost:8080";
var url = protocol + "://" + host + "/live/stream";
ws = new WebSocket(url);
ws.binaryType = 'arraybuffer';
ws.addEventListener("open",onOpenWebSocket,false);
ws.addEventListener("close",onCloseWebSocket,false);
ws.addEventListener("message",onMessageWebSocket,false);
window.addEventListener("unload",onUnload,false);
...
function onMessageWebSocket(event){
var blob = new Blob([event.data], {type: 'video/mp4'});
var rb = blob.slice(0, blob.size, 'video/mp4');
video.src = window.URL.createObjectURL(rb);
}
...
</script>
I think I need to obtain MP4 data as stream using JavaCV, but don't know how to do that. Please help.
Any comment, suggestions would be appreciated. Thank you.
I'm pretty new to the HTML5 audio api: I've read some of the related articles at HTML5 Rocks, but it can be a little tricky flipping between Javascript and Dart at times.
In any case, I've been experimenting with HTML5 Audio in Dart. To produce sound effects for a simple game, I created a class as follows. I created an AudioContext, loaded sound data into SoundBuffers, and when the sound needed to be played, created an AudioBufferSourceNode via which to play the data stored in the buffers:
class Sfx {
AudioContext audioContext;
List<Map> soundList;
int soundFiles;
Sfx() {
audioContext = new AudioContext();
soundList = new List<Map>();
var soundsToLoad = [
{"name": "MISSILE", "url": "SFX/missile.wav"},
{"name": "EXPLOSION", "url": "SFX/explosion.wav"}
];
soundFiles = soundsToLoad.length;
for (Map sound in soundsToLoad) {
initSound(sound);
}
}
bool allSoundsLoaded() => (soundFiles == 0);
void initSound(Map soundMap) {
HttpRequest req = new HttpRequest();
req.open('GET', soundMap["url"], true);
req.responseType = 'arraybuffer';
req.on.load.add((Event e) {
audioContext.decodeAudioData(
req.response,
(var buffer) {
// successful decode
print("...${soundMap["name"]} loaded...");
soundList.add({"name": soundMap["name"], "buffer": buffer});
soundFiles--;
},
(var error) {
print("error loading ${soundMap["name"]}");
}
);
});
req.send();
}
void sfx(AudioBuffer buffer) {
AudioBufferSourceNode source = audioContext.createBufferSource();
source.connect(audioContext.destination, 0, 0);
source.buffer = buffer;
source.start(0);
}
void playSound(String sound) {
for (Map m in soundList) {
print(m);
if (m["name"] == sound) {
sfx(m["buffer"]);
break;
}
}
}
}
(The sound effects are in a folder "SFX". Now that I look at the code, there are probably a million better ways to organise the data, but that's besides the point right now.) I am able to play sound effects by creating an instance of Sfx and calling the method playSound.
e.g.
#import('dart:html');
#source('sfx.dart');
Sfx sfx;
void main() {
sfx = new Sfx();
window.on.keyUp.add((KeyboardEvent keX) {
sfx.playSound("MISSILE");
});
}
(Edit: added code to play sound when a key is hit.)
The problem is: although with the dart2js Javascript, the sound effects play as expected in Safari, when they are played in Dartium or (with the dart2js Javascript) in Chrome, they are distorted. (In Firefox, there are even worse problems!)
Is there anything obvious that I have neglected to do or that I need to take into account? Otherwise, are there any references or tutorials, preferably in a Dart context, that might help?
thanks for trying Dart!
First off, Firefox doesn't support Web Audio API (yet?) Chrome and Safari support Web Audio API. You can track adoption of Web Audio API here: http://caniuse.com/#feat=audio-api
Second, please try this Web Audio API sample in Dartium: https://github.com/dart-lang/dart-html5-samples/tree/master/web/webaudio/intro You will need to clone the repo first and run it locally. This sample works for me locally.
This sounds more like a bug report. If the sample from dart-html5-samples works for you, but your above code continues to be distorted, please open a bug at http://dartbug.com/new so we can take a look.
One thing to consider is waiting until the specific MISSLE sound is loaded before hooking up the keyUp handler.