当前位置:  开发笔记 > 编程语言 > 正文

从视频C#中提取帧

如何解决《从视频C#中提取帧》经验,为你挑选了3个好方法。

我正在尝试制作一款使用相机录制视频并处理视频图像的应用.这就是我想要的.首先,我的应用程序使用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 Task 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();





    });


}   

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++;
    }
}

希望有一天能对某人有所帮助。



1> Brendan Kend..:

在与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++;
    }
}

希望有一天能对某人有所帮助。



2> Alamakanambr..:

我昨天才知道这件事.

这是一个完整且易于理解的示例,它选择视频文件并在第一秒视频中保存快照.

您可以拍摄适合您项目的部分并更改其中一些(即从相机获取视频分辨率)

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
        List encodingPropertiesToRetrieve = 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



3> 小智..:

使用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();
}

推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有