我正在尝试制作一款使用相机录制视频并处理视频图像的应用.这就是我想要的.首先,我的应用程序使用Torch录制了10秒的视频.其次,我使用一种方法来播放视频以查看我录制的内容.
我坚持三件事.
如何将视频转换为单独的帧(图像)?
是否有可能在录制视频时异步转换视频?
当我将视频转换为单独的帧时,如何使用它们?它们是JPEG吗?我可以简单地将它们显示为图像吗?等等.
主要代码:
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; } } } }
图书馆类:
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 Taskinit() { 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(); }); }
Brendan Kend.. 10
在与Accord遇到许多麻烦之后,我最终使用MediaToolkit解决了类似的问题。
我需要为视频的每一秒保存一个图像:
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++; } }
希望有一天能对某人有所帮助。
在与Accord遇到许多麻烦之后,我最终使用MediaToolkit解决了类似的问题。
我需要为视频的每一秒保存一个图像:
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++; } }
希望有一天能对某人有所帮助。
我昨天才知道这件事.
这是一个完整且易于理解的示例,它选择视频文件并在第一秒视频中保存快照.
您可以拍摄适合您项目的部分并更改其中一些(即从相机获取视频分辨率)
1)和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 ListencodingPropertiesToRetrieve = new List (); encodingPropertiesToRetrieve.Add("System.Video.FrameHeight"); encodingPropertiesToRetrieve.Add("System.Video.FrameWidth"); IDictionary 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(); } }
如果要在xaml Image中显示帧,则应使用imageStream
BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(imageStream); XAMLImage.Source = bitmapImage;
如果你想提取更多帧,也有 composition.GetThumbnailsAsync
2)当你的计时器滴答作响时,使用你的mediaCapture
使用ffmpeg并安装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(); }