J'essaie de créer une application qui utilise l'appareil photo pour enregistrer une vidéo et traiter les images de la vidéo. Voici ce que je veux. Tout d'abord, mon application enregistre une vidéo de 10 secondes avec Torch. Deuxièmement, j'utilise une méthode pour lire la vidéo pour voir ce que j'enregistre.
Je suis coincé sur trois choses.
Code principal:
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace App3
{
public sealed partial class MainPage : Page
{
DispatcherTimer D;
double basetimer = 0;
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
D = new DispatcherTimer();
D.Interval = new TimeSpan(0, 0, 1);
D.Tick += timer_Tick;
txt.Text = basetimer.ToString();
Play.IsEnabled = false;
}
public Library Library = new Library();
public object PreviewImage { get; private set; }
void timer_Tick(object sender, object e)
{
basetimer = basetimer - 1;
txt.Text = basetimer.ToString();
if (basetimer == 0)
{
D.Stop();
Preview.Source = null;
Library.Stop();
Record.IsEnabled = false;
Play.IsEnabled = true;
Clear.IsEnabled = true;
if (Library._tc.Enabled)
{
Library._tc.Enabled = false;
}
}
}
private void Record_Click(object sender, RoutedEventArgs e)
{
if (Library.Recording)
{
Preview.Source = null;
Library.Stop();
Record.Icon = new SymbolIcon(Symbol.Video);
}
else
{
basetimer = 11;
D.Start();
//D.Tick += timer_Tick;
Display.Source = null;
Library.Record(Preview);
Record.Icon = new SymbolIcon(Symbol.VideoChat);
Record.IsEnabled = false;
Play.IsEnabled = false;
}
}
private async void Play_Click(object sender, RoutedEventArgs e)
{
await Library.Play(Dispatcher, Display);
//Extract_Image_From_Video(Library.buffer);
}
private void Clear_Click(object sender, RoutedEventArgs e)
{
Display.Source = null;
Record.Icon = new SymbolIcon(Symbol.Video);
txt.Text = "0";
basetimer= 0;
Play.IsEnabled = false;
Record.IsEnabled =true;
if (Library.capture != null)
{
D.Stop();
Library.Recording = false;
Preview.Source = null;
Library.capture.Dispose();
Library.capture = null;
basetimer = 11;
}
}
}
}
Classe de bibliothèque:
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Media.Capture;
using Windows.Media.Devices;
using Windows.Media.MediaProperties;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Graphics.Imaging;
using Emgu.CV.Structure;
using Emgu.CV;
using System.Collections.Generic;
public class Library
{
private const string videoFilename = "video.mp4";
private string filename;
public MediaCapture capture;
public InMemoryRandomAccessStream buffer;
public static bool Recording;
public TorchControl _tc;
public int basetimer ;
public async Task<bool> init()
{
if (buffer != null)
{
buffer.Dispose();
}
buffer = new InMemoryRandomAccessStream();
if (capture != null)
{
capture.Dispose();
}
try
{
if (capture == null)
{
var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
DeviceInformation cameraDevice =
allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null &&
x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
capture = new MediaCapture();
var mediaInitSettings = new MediaCaptureInitializationSettings { VideoDeviceId = cameraDevice.Id };
// Initialize
try
{
await capture.InitializeAsync(mediaInitSettings);
var videoDev = capture.VideoDeviceController;
_tc = videoDev.TorchControl;
Recording = false;
_tc.Enabled = false;
}
catch (UnauthorizedAccessException)
{
Debug.WriteLine("UnauthorizedAccessExeption>>");
}
catch (Exception ex)
{
Debug.WriteLine("Exception when initializing MediaCapture with {0}: {1}", cameraDevice.Id, ex.ToString());
}
}
capture.Failed += (MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs) =>
{
Recording = false;
_tc.Enabled = false;
throw new Exception(string.Format("Code: {0}. {1}", errorEventArgs.Code, errorEventArgs.Message));
};
}
catch (Exception ex)
{
if (ex.InnerException != null && ex.InnerException.GetType() == typeof(UnauthorizedAccessException))
{
throw ex.InnerException;
}
throw;
}
return true;
}
public async void Record(CaptureElement preview)
{
await init();
preview.Source = capture;
await capture.StartPreviewAsync();
await capture.StartRecordToStreamAsync(MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto), buffer);
if (Recording) throw new InvalidOperationException("cannot excute two records at the same time");
Recording = true;
_tc.Enabled = true;
}
public async void Stop()
{
await capture.StopRecordAsync();
Recording = false;
_tc.Enabled = false;
}
public async Task Play(CoreDispatcher dispatcher, MediaElement playback)
{
IRandomAccessStream video = buffer.CloneStream();
if (video == null) throw new ArgumentNullException("buffer");
StorageFolder storageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
if (!string.IsNullOrEmpty(filename))
{
StorageFile original = await storageFolder.GetFileAsync(filename);
await original.DeleteAsync();
}
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
StorageFile storageFile = await storageFolder.CreateFileAsync(videoFilename, CreationCollisionOption.GenerateUniqueName);
filename = storageFile.Name;
using (IRandomAccessStream fileStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(video.GetInputStreamAt(0), fileStream.GetOutputStreamAt(0));
await video.FlushAsync();
video.Dispose();
}
IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read);
playback.SetSource(stream, storageFile.FileType);
playback.Play();
});
}
Je l'ai compris hier.
Voici un exemple complet et facile à comprendre avec la sélection d'un fichier vidéo et l'enregistrement d'un instantané en 1ère seconde de vidéo.
Vous pouvez prendre des pièces adaptées à votre projet et en modifier certaines (par exemple, obtenir la résolution vidéo de la caméra)
1) et 3)
TimeSpan timeOfFrame = new TimeSpan(0, 0, 1);
//pick mp4 file
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(".mp4");
StorageFile pickedFile = await picker.PickSingleFileAsync();
if (pickedFile == null)
{
return;
}
///
//Get video resolution
List<string> encodingPropertiesToRetrieve = new List<string>();
encodingPropertiesToRetrieve.Add("System.Video.FrameHeight");
encodingPropertiesToRetrieve.Add("System.Video.FrameWidth");
IDictionary<string, object> encodingProperties = await pickedFile.Properties.RetrievePropertiesAsync(encodingPropertiesToRetrieve);
uint frameHeight = (uint)encodingProperties["System.Video.FrameHeight"];
uint frameWidth = (uint)encodingProperties["System.Video.FrameWidth"];
///
//Use Windows.Media.Editing to get ImageStream
var clip = await MediaClip.CreateFromFileAsync(pickedFile);
var composition = new MediaComposition();
composition.Clips.Add(clip);
var imageStream = await composition.GetThumbnailAsync(timeOfFrame, (int)frameWidth, (int)frameHeight, VideoFramePrecision.NearestFrame);
///
//generate bitmap
var writableBitmap = new WriteableBitmap((int)frameWidth, (int)frameHeight);
writableBitmap.SetSource(imageStream);
//generate some random name for file in PicturesLibrary
var saveAsTarget = await KnownFolders.PicturesLibrary.CreateFileAsync("IMG" + Guid.NewGuid().ToString().Substring(0, 4) + ".jpg");
//get stream from bitmap
Stream stream = writableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
using (var writeStream = await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, writeStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)writableBitmap.PixelWidth,
(uint)writableBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
using (var outputStream = writeStream.GetOutputStreamAt(0))
{
await outputStream.FlushAsync();
}
}
Si vous souhaitez afficher des cadres dans Image xaml, vous devez utiliser imageStream
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);
XAMLImage.Source = bitmapImage;
Si vous souhaitez extraire plus de cadres, il y a aussi composition.GetThumbnailsAsync
2) Utilisez votre mediaCapture, lorsque votre minuterie tourne
J'ai fini par utiliser MediaToolkit pour résoudre un problème similaire après avoir eu une tonne de problèmes avec Accord.
J'avais besoin de sauvegarder une image pour chaque seconde d'une vidéo:
using (var engine = new Engine())
{
var mp4 = new MediaFile { Filename = mp4FilePath };
engine.GetMetadata(mp4);
var i = 0;
while (i < mp4.Metadata.Duration.Seconds)
{
var options = new ConversionOptions { Seek = TimeSpan.FromSeconds(i) };
var outputFile = new MediaFile { Filename = string.Format("{0}\\image-{1}.jpeg", outputPath, i) };
engine.GetThumbnail(mp4, outputFile, options);
i++;
}
}
J'espère que cela aidera quelqu'un un jour.
Utilisez ffmpeg et installez Accord.Video.FFMPEG
using (var vFReader = new VideoFileReader())
{
vFReader.Open("video.mp4");
for (int i = 0; i < vFReader.FrameCount; i++)
{
Bitmap bmpBaseOriginal = vFReader.ReadVideoFrame();
}
vFReader.Close();
}