Benutzerdefinierte VideoeffekteCustom video effects

In diesem Artikel wird beschrieben, wie Sie eine Windows-Runtime-Komponente erstellen, die die IBasicVideoEffect-Schnittstelle implementiert, mit der Sie benutzerdefinierte Effekte für Videostreams erstellen können.This article describes how to create a Windows Runtime component that implements the IBasicVideoEffect interface to create custom effects for video streams. Benutzerdefinierte Effekte können mit verschiedenen Windows-Runtime-APIs verwendet werden, z. B. MediaCapture, die den Zugriff auf die Kamera eines Gerätes ermöglicht, sowie MediaComposition, mit der Sie komplexe Kompositionen aus Medienclips erstellen können.Custom effects can be used with several different Windows Runtime APIs including MediaCapture, which provides access to a device's camera, and MediaComposition, which allows you to create complex compositions out of media clips.

Hinzufügen eines benutzerdefinierten Effekts zu Ihrer AppAdd a custom effect to your app

Sie definieren einen benutzerdefinierte Videoefekt in einer Klasse, die die IBasicVideoEffect-Schnittstelle implementiert.A custom video effect is defined in a class that implements the IBasicVideoEffect interface. Diese Klasse kann nicht direkt in Ihr App-Projekt integriert werden.This class can't be included directly in your app's project. Stattdessen müssen Sie eine Windows-Runtime-Komponente verwenden, um Ihre Videoeffektklasse zu hosten.Instead, you must use a Windows Runtime component to host your video effect class.

Fügen Sie eine Windows-Runtime Komponente für den Videoeffekt hinzu.Add a Windows Runtime component for your video effect

  1. Wechseln Sie in Microsoft Visual Studio bei geöffneter Projektmappe zum Menü Datei, und wählen Sie Hinzufügen->Neues Projekt aus.In Microsoft Visual Studio, with your solution open, go to the File menu and select Add->New Project.
  2. Wählen Sie den Projekttyp Komponente für Windows-Runtime (Universal Windows) aus.Select the Windows Runtime Component (Universal Windows) project type.
  3. Benennen Sie in diesem Beispiel das Projekt videoeffectcomponent.For this example, name the project VideoEffectComponent. Auf diesen Namen wird später im Code verwiesen.This name will be referenced in code later.
  4. Klicken Sie auf OK.Click OK.
  5. Die Projektvorlage erstellt eine Klasse namens „Class1.cs“.The project template creates a class called Class1.cs. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Symbol für „Class1.cs“, und wählen Sie Umbenennen aus.In Solution Explorer, right-click the icon for Class1.cs and select Rename.
  6. Benennen Sie die Datei in ExampleVideoEffect.csum.Rename the file to ExampleVideoEffect.cs. Visual Studio zeigt eine Eingabeaufforderung an, in der Sie gefragt werden, ob Sie alle Verweise mit dem neuen Namen aktualisieren möchten.Visual Studio will show a prompt asking if you want to update all references to the new name. Klicken Sie auf Ja.Click Yes.
  7. Öffnen Sie ExampleVideoEffect.cs , und aktualisieren Sie die Klassendefinition, um die ibasicvideoeffect -Schnittstelle zu implementieren.Open ExampleVideoEffect.cs and update the class definition to implement the IBasicVideoEffect interface.
public sealed class ExampleVideoEffect : IBasicVideoEffect

Sie müssen die folgenden Namespaces in Ihre Effektklassendatei aufnehmen, um auf alle Typen, die in den Beispielen in diesem Artikel verwendet werden, zugreifen zu können.You need to include the following namespaces in your effect class file in order to access all of the types used in the examples in this article.

using Windows.Media.Effects;
using Windows.Media.MediaProperties;
using Windows.Foundation.Collections;
using Windows.Graphics.DirectX.Direct3D11;
using Windows.Graphics.Imaging;

Implementieren der IBasicVideoEffect-Schnittstelle mit SoftwareverarbeitungImplement the IBasicVideoEffect interface using software processing

Der Videoeffekt muss alle Methoden und Eigenschaften der IBasicVideoEffect-Schnittstelle implementieren.Your video effect must implement all of the methods and properties of the IBasicVideoEffect interface. In diesem Abschnitt wird der Prozess einer einfachen Implementierung der Schnittstelle erläutert, bei dem die Softwareverarbeitung verwendet wird.This section walks you through a simple implementation of this interface that uses software processing.

Close-MethodeClose method

Das System ruft die Close-Methode für die Klasse auf, wenn der Effekt beendet werden soll.The system will call the Close method on your class when the effect should shut down. Sie sollten diese Methode verwenden, um alle Ressourcen, die Sie erstellt haben, zu löschen.You should use this method to dispose of any resources you have created. Das Argument für die-Methode ist ein mediaeffectclosedreason -Element, mit dem Sie wissen können, ob der Effekt normal geschlossen wurde, wenn ein Fehler aufgetreten ist oder der Effekt das erforderliche Codierungsformat nicht unterstützt.The argument to the method is a MediaEffectClosedReason that lets you know whether the effect was closed normally, if an error occurred, or if the effect does not support the required encoding format.

public void Close(MediaEffectClosedReason reason)
{
    // Dispose of effect resources
}

DiscardQueuedFrames-MethodeDiscardQueuedFrames method

Die DiscardQueuedFrames-Methode wird aufgerufen, wenn der Effekt zurückgesetzt werden soll.The DiscardQueuedFrames method is called when your effect should reset. Ein typisches Szenario hierfür ist, wenn der Effekt zuvor verarbeitete Frames zum Verarbeiten des aktuellen Frames speichert.A typical scenario for this is if your effect stores previously processed frames to use in processing the current frame. Wenn diese Methode aufgerufen wird, sollten Sie die zuvor gespeicherten Frames löschen.When this method is called, you should dispose of the set of previous frames you saved. Diese Methode kann verwendet werden, um alle Zustände im Zusammenhang mit den vorherigen Frames zurückzusetzen, nicht nur Videoframes, die sich angesammelt haben.This method can be used to reset any state related to previous frames, not only accumulated video frames.

private int frameCount;
public void DiscardQueuedFrames()
{
    frameCount = 0;
}

IsReadOnly-EigenschaftIsReadOnly property

Die IsReadOnly-Eigenschaft teilt dem System mit, ob Ihr Effekt in die Ausgabe des Effekts schreibt.The IsReadOnly property lets the system know if your effect will write to the output of the effect. Wenn Ihre App die Videoframes nicht ändert (z. B. ein Effekt, der nur eine Analyse der Videoframes durchführt), sollten Sie diese Eigenschaft auf „true“ festlegen. Dann kopiert das System für Sie die Frameeingabe in die Frameausgabe.If your app does not modify the video frames (for example, an effect that only performs analysis of the video frames), you should set this property to true, which will cause the system to efficiently copy the frame input to the frame output for you.

Tipp

Wenn die IsReadOnly-Eigenschaft auf „true“ festgelegt ist, kopiert das System den Eingabeframe in den Ausgabeframe, bevor ProcessFrame aufgerufen wird.When the IsReadOnly property is set to true, the system copies the input frame to the output frame before ProcessFrame is called. Das Festlegen der IsReadOnly-Eigenschaft auf „true“ schränkt Sie nicht darin ein, in die Ausgabeframes in ProcessFrame zu schreiben.Setting the IsReadOnly property to true does not restrict you from writing to the effect's output frames in ProcessFrame.

public bool IsReadOnly { get { return false; } }

SetEncodingProperties-MethodeSetEncodingProperties method

Das System ruft SetEncodingProperties für den Effekt auf, um Ihnen die Codierungseigenschaften für den Videostream mitzuteilen, für den der Effekt gilt.The system calls SetEncodingProperties on your effect to let you know the encoding properties for the video stream upon which the effect is operating. Diese Methode bietet auch einen Verweis auf das Direct3D-Gerät, welches für das Hardwarerendering verwendet wird.This method also provides a reference to the Direct3D device used for hardware rendering. Die Verwendung dieses Geräts wird im Beispiel zur Hardwareverarbeitung weiter unten in diesem Artikel gezeigt.The usage of this device is shown in the hardware processing example later in this article.

private VideoEncodingProperties encodingProperties;
public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device)
{
    this.encodingProperties = encodingProperties;
}

SupportedEncodingProperties-EigenschaftSupportedEncodingProperties property

Das System überprüft die SupportedEncodingProperties-Eigenschaft, um festzustellen, welche Codierungseigenschaften von dem Effekt unterstützt werden.The system checks the SupportedEncodingProperties property to determine which encoding properties are supported by your effect. Beachten Sie Folgendes: Wenn der Nutzer Ihres Effekts das Video mit den von Ihnen angegebenen Eigenschaften nicht codieren kann, wird Close für den Effekt aufgerufen und er wird aus der Videopipeline entfernt.Note that if the consumer of your effect can't encode video using the properties you specify, it will call Close on your effect and will remove your effect from the video pipeline.

public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties
{            
    get
    {
        var encodingProperties = new VideoEncodingProperties();
        encodingProperties.Subtype = "ARGB32";
        return new List<VideoEncodingProperties>() { encodingProperties };

        // If the list is empty, the encoding type will be ARGB32.
        // return new List<VideoEncodingProperties>();
    }
}

Hinweis

Wenn Sie eine leere Liste mit VideoEncodingProperties-Objekten von SupportedEncodingProperties zurückgeben, verwendet das System standardmäßig die ARGB32-Codierung.If you return an empty list of VideoEncodingProperties objects from SupportedEncodingProperties, the system will default to ARGB32 encoding.

 

SupportedMemoryTypes-EigenschaftSupportedMemoryTypes property

Das System überprüft die SupportedMemoryTypes Eigenschaft, um festzustellen, ob der Effekt auf Videoframes im Softwarespeicher oder im Hardwarearbeitsspeicher (GPU) zugreift.The system checks the SupportedMemoryTypes property to determine whether your effect will access video frames in software memory or in hardware (GPU) memory. Wenn Sie MediaMemoryTypes.Cpu zurückgeben, werden an Ihren Effekt Ein- und Ausgabeframes übergeben, die Bilddaten in SoftwareBitmap-Objekten enthalten.If you return MediaMemoryTypes.Cpu, your effect will be passed input and output frames that contain image data in SoftwareBitmap objects. Wenn Sie MediaMemoryTypes.Gpu zurückgeben, werden an Ihren Effekt Ein- und Ausgabeframes übergeben, die Bilddaten in IDirect3DSurface-Objekten enthalten.If you return MediaMemoryTypes.Gpu, your effect will be passed input and output frames that contain image data in IDirect3DSurface objects.

public MediaMemoryTypes SupportedMemoryTypes { get { return MediaMemoryTypes.Cpu; } }

Hinweis

Wenn Sie MediaMemoryTypes.GpuAndCpu angeben, verwendet das System entweder den GPU- oder Systemarbeitsspeicher, je nachdem, welcher für die Pipeline effizienter ist.If you specify MediaMemoryTypes.GpuAndCpu, the system will use either GPU or system memory, whichever is more efficient for the pipeline. Wenn Sie diesen Wert verwenden, müssen Sie in der ProcessFrame-Methode prüfen, ob SoftwareBitmap oder IDirect3DSurface, das an die Methode übergeben wird, Daten enthält, und den Frame dann entsprechend verarbeiten.When using this value, you must check in the ProcessFrame method to see whether the SoftwareBitmap or IDirect3DSurface passed into the method contains data, and then process the frame accordingly.

 

TimeIndependent-EigenschaftTimeIndependent property

Die TimeIndependent-Eigenschaft teilt dem System mit, dass der Effekt kein einheitliches Timing erfordert.The TimeIndependent property lets the system know if your effect does not require uniform timing. Bei Festlegung auf „true“ kann das System Optimierungen verwenden, die die Leistung des Effekts verbessern.When set to true, the system can use optimizations that enhance effect performance.

public bool TimeIndependent { get { return true; } }

SetProperties-MethodeSetProperties method

Die SetProperties-Methode ermöglicht es der App, die Ihren Effekt verwendet, die Effektparameter anzupassen.The SetProperties method allows the app that is using your effect to adjust effect parameters. Die Eigenschaften werden als IPropertySet-Zuordnung von Eigenschaftsnamen und -werten übergeben.Properties are passed as an IPropertySet map of property names and values.

private IPropertySet configuration;
public void SetProperties(IPropertySet configuration)
{
    this.configuration = configuration;
}

In diesem einfachen Beispiel werden die Pixel in jedem Videoframe entsprechend einem angegebenen Wert abgeblendet.This simple example will dim the pixels in each video frame according to a specified value. Eine Eigenschaft wird deklariert, und „TryGetValue“ wird verwendet, um den von der aufrufenden App festgelegten Wert abzurufen.A property is declared and TryGetValue is used to get the value set by the calling app. Wenn kein Wert festgelegt wurde, wird der Standardwert 0,5 verwendet.If no value was set, a default value of .5 is used.

public double FadeValue
{
    get
    {
        object val;
        if (configuration != null && configuration.TryGetValue("FadeValue", out val))
        {
            return (double)val;
        }
        return .5;
    }
}

ProcessFrame-MethodeProcessFrame method

Die ProcessFrame-Methode ist die Stelle, an der Ihr Effekt die Bilddaten des Videos ändert.The ProcessFrame method is where your effect modifies the image data of the video. Die Methode wird einmal pro Frame aufgerufen, und ihr wird ein ProcessVideoFrameContext-Objekt übergeben.The method is called once per frame and is passed a ProcessVideoFrameContext object. Dieses Objekt enthält ein VideoFrame-Eingabeobjekt, das den eingehenden Frame umfasst, der verarbeitet werden soll, und ein VideoFrame-Ausgabeobjekt, in das Sie Bilddaten schreiben, die dem Rest der Videopipeline übergeben werden.This object contains an input VideoFrame object that contains the incoming frame to be processed and an output VideoFrame object to which you write image data that will be passed on to rest of the video pipeline. Jedes dieser VideoFrame-Objekte verfügt über eine SoftwareBitmap-Eigenschaft und eine Direct3DSurface-Eigenschaft. Welche aber verwendet werden kann, wird von dem Wert bestimmt, den Sie von der SupportedMemoryTypes-Eigenschaft zurückgeben.Each of these VideoFrame objects has a SoftwareBitmap property and a Direct3DSurface property, but which of these can be used is determined by the value you returned from the SupportedMemoryTypes property.

Dieses Beispiel zeigt eine einfache Implementierung der ProcessFrame-Methode mit Softwareverarbeitung.This example shows a simple implementation of the ProcessFrame method using software processing. Weitere Informationen zum Arbeiten mit SoftwareBitmap-Objekten finden Sie unter Bildverarbeitung.For more information about working with SoftwareBitmap objects, see Imaging. Ein Beispiel für die ProcessFrame-Implementierung mit Hardwareverarbeitung wird später in diesem Artikel gezeigt.An example ProcessFrame implementation using hardware processing is shown later in this article.

Für den Zugriff auf den Datenpuffer einer SoftwareBitmap ist COM-Interoperabilität erforderlich. Daher sollten Sie den Namespace System.Runtime.InteropServices in Ihre Effektklassendatei aufnehmen.Accessing the data buffer of a SoftwareBitmap requires COM interop, so you should include the System.Runtime.InteropServices namespace in your effect class file.

using System.Runtime.InteropServices;

Fügen Sie den folgenden Code in den Namespace für den Effekt ein, um die Schnittstelle für den Zugriff auf den Bildpuffer zu importieren.Add the following code inside the namespace for your effect to import the interface for accessing the image buffer.

[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
    void GetBuffer(out byte* buffer, out uint capacity);
}

Hinweis

Da diese Technik auf einen systemeigenen, nicht verwalteten Bildpuffer zugreift, müssen Sie Ihr Projekt konfigurieren, um unsicheren Code zuzulassen.Because this technique accesses a native, unmanaged image buffer, you will need to configure your project to allow unsafe code.

  1. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Projekt videoeffectcomponent, und wählen Sie Eigenschaftenaus.In Solution Explorer, right-click the VideoEffectComponent project and select Properties.
  2. Wählen Sie die Registerkarte Build aus.Select the Build tab.
  3. Aktivieren Sie das Kontrollkästchen unsicheren Code zulassen .Select the Allow unsafe code check box.

 

Sie können nun die ProcessFrame-Methodenimplementierung hinzufügen.Now you can add the ProcessFrame method implementation. Zunächst erhält diese Methode ein BitmapBuffer-Objekt aus den Ein- und Ausgabesoftwarebitmaps.First, this method obtains a BitmapBuffer object from both the input and output software bitmaps. Beachten Sie, dass der Ausgabeframe zum Schreiben und die Eingabe zum Lesen geöffnet wird.Note that the output frame is opened for writing and the input for reading. Als Nächstes wird ein IMemoryBufferReference-Objekt für jeden Puffer durch Aufrufen von CreateReference abgerufen.Next, an IMemoryBufferReference is obtained for each buffer by calling CreateReference. Danach wird der tatsächliche Datenpuffer durch Umwandeln der IMemoryBufferReference-Objekte wie die oben definierte COMInterop-Schnittstelle, IMemoryByteAccess, und anschließendes Aufrufen von GetBuffer abgerufen.Then, the actual data buffer is obtained by casting the IMemoryBufferReference objects as the COM interop interface defined above, IMemoryByteAccess, and then calling GetBuffer.

Nun, da die Datenpuffer abgerufen wurden, können Sie aus dem Eingabepuffer lesen und in den Ausgabepuffer schreiben.Now that the data buffers have been obtained, you can read from the input buffer and write to the output buffer. Das Layout des Puffers wird durch Aufrufen von GetPlaneDescription abgerufen, das Informationen über die Breite und den anfänglichen Versatz des Puffers bereitstellt.The layout of the buffer is obtained by calling GetPlaneDescription, which provides information on the width, stride, and initial offset of the buffer. Die Bits pro Pixel werden durch die Codierungseigenschaften bestimmt, die zuvor mit der SetEncodingProperties-Methode festgelegt wurden.The bits per pixel is determined by the encoding properties set previously with the SetEncodingProperties method. Anhand der Informationen zum Pufferformat wird der Index im Puffer für jedes Pixel gefunden.The buffer format information is used to find the index into the buffer for each pixel. Der Pixelwert aus dem Quellpuffer wird in den Zielpuffer kopiert, wobei die Farbwerte mit der FadeValue-Eigenschaft multipliziert werden, die für diesen Effekt definiert ist, um sie um den angegebenen Wert abzublenden.The pixel value from the source buffer is copied into the target buffer, with the color values being multiplied by the FadeValue property defined for this effect to dim them by the specified amount.

public unsafe void ProcessFrame(ProcessVideoFrameContext context)
{
    using (BitmapBuffer buffer = context.InputFrame.SoftwareBitmap.LockBuffer(BitmapBufferAccessMode.Read))
    using (BitmapBuffer targetBuffer = context.OutputFrame.SoftwareBitmap.LockBuffer(BitmapBufferAccessMode.Write))
    {
        using (var reference = buffer.CreateReference())
        using (var targetReference = targetBuffer.CreateReference())
        {
            byte* dataInBytes;
            uint capacity;
            ((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacity);

            byte* targetDataInBytes;
            uint targetCapacity;
            ((IMemoryBufferByteAccess)targetReference).GetBuffer(out targetDataInBytes, out targetCapacity);

            var fadeValue = FadeValue;

            // Fill-in the BGRA plane
            BitmapPlaneDescription bufferLayout = buffer.GetPlaneDescription(0);
            for (int i = 0; i < bufferLayout.Height; i++)
            {
                for (int j = 0; j < bufferLayout.Width; j++)
                {

                    byte value = (byte)((float)j / bufferLayout.Width * 255);

                    int bytesPerPixel = 4; 
                    if (encodingProperties.Subtype != "ARGB32")
                    {
                        // If you support other encodings, adjust index into the buffer accordingly
                    }
                    

                    int idx = bufferLayout.StartIndex + bufferLayout.Stride * i + bytesPerPixel * j;

                    targetDataInBytes[idx + 0] = (byte)(fadeValue * (float)dataInBytes[idx + 0]);
                    targetDataInBytes[idx + 1] = (byte)(fadeValue * (float)dataInBytes[idx + 1]);
                    targetDataInBytes[idx + 2] = (byte)(fadeValue * (float)dataInBytes[idx + 2]);
                    targetDataInBytes[idx + 3] = dataInBytes[idx + 3];
                }
            }
        }
    }
}

Implementieren der IBasicVideoEffect-Schnittstelle mit HardwareverarbeitungImplement the IBasicVideoEffect interface using hardware processing

Das Erstellen eines benutzerdefinierten Videoeffekts mit der Hardwareverarbeitung (GPU) ist nahezu identisch mit der oben beschriebenen Verfahrensweise mit Softwareverarbeitung.Creating a custom video effect by using hardware (GPU) processing is almost identical to using software processing as described above. In diesem Abschnitt werden die wenigen Unterschiede in einem Effekt erläutert, bei dem die Hardwareverarbeitung verwendet wird.This section will show the few differences in an effect that uses hardware processing. In diesem Beispiel wird die Win2D-Windows-Runtime-API verwendet.This example uses the Win2D Windows Runtime API. Weitere Informationen zur Verwendung von Win2D finden Sie in der Win2D-Dokumentation.For more information about using Win2D, see the Win2D documentation.

Führen Sie die folgenden Schritte aus, um das Win2D-NuGet-Paket zu dem Projekt hinzuzufügen, das Sie wie im Abschnitt Hinzufügen eines benutzerdefinierten Effekts zu Ihrer App zu Beginn dieses Artikels beschrieben erstellt haben.Use the following steps to add the Win2D NuGet package to the project you created as described in the Add a custom effect to your app section at the beginning of this article.

So fügen Sie das Win2D-NuGet-Paket zum Effektprojekt hinzuTo add the Win2D NuGet package to your effect project

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt VideoEffectComponent, und wählen Sie NuGet-Pakete verwalten aus.In Solution Explorer, right-click the VideoEffectComponent project and select Manage NuGet Packages.
  2. Wählen Sie oben im Fenster die Registerkarte Durchsuchen aus.At the top of the window, select the Browse tab.
  3. Geben Sie im Suchfeld Win2D ein.In the search box, enter Win2D.
  4. Wählen Sie Win2D.uwp und anschließend im rechten Bereich Installieren aus.Select Win2D.uwp, and then select Install in the right pane.
  5. Im Dialogfeld Änderungen überprüfen wird das zu installierende Paket angezeigt.The Review Changes dialog shows you the package to be installed. Klicken Sie auf OK.Click OK.
  6. Akzeptieren Sie die Paketlizenz.Accept the package license.

Zusätzlich zu den Namespaces, die bei der grundlegenden Einrichtung des Projekts verwendet wurden, müssen Sie die folgenden von Win2D bereitgestellten Namespaces hinzufügen.In addition to the namespaces included in the basic project setup, you will need to include the following namespaces provided by Win2D.

using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas;

Da dieser Effekt GPU-Speicher für die Aktionen mit den Bilddaten verwendet, sollten Sie MediaMemoryTypes.Gpu aus der SupportedMemoryTypes-Eigenschaft zurückgeben.Because this effect will use GPU memory for operating on the image data, you should return MediaMemoryTypes.Gpu from the SupportedMemoryTypes property.

public MediaMemoryTypes SupportedMemoryTypes { get { return MediaMemoryTypes.Gpu; } }

Legen Sie die Codierungseigenschaften, die vom Effekt unterstützt werden sollen, mit der SupportedEncodingProperties-Eigenschaft fest.Set the encoding properties that your effect will support with the SupportedEncodingProperties property. Wenn Sie mit Win2D arbeiten, müssen Sie die ARGB32-Codierung verwenden.When working with Win2D, you must use ARGB32 encoding.

public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties {
    get
    {
        var encodingProperties = new VideoEncodingProperties();
        encodingProperties.Subtype = "ARGB32";
        return new List<VideoEncodingProperties>() { encodingProperties };
    }
}

Verwenden Sie die SetEncodingProperties-Methode, um ein neues Win2D-CanvasDevice-Objekt vom IDirect3DDevice zu erstellen, das an die Methode übergeben wird.Use the SetEncodingProperties method to create a new Win2D CanvasDevice object from the IDirect3DDevice passed into the method.

private CanvasDevice canvasDevice;
public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device)
{
    canvasDevice = CanvasDevice.CreateFromDirect3D11Device(device);
}

Die Implementierung von SetProperties ist mit dem vorherigen Beispiel zur Softwareverarbeitung identisch.The SetProperties implementation is identical to the previous software processing example. Bei diesem Beispiel wird eine BlurAmount-Eigenschaft verwendet, um einen Win2D-Weichzeichnereffekt zu konfigurieren.This example uses a BlurAmount property to configure a Win2D blur effect.

private IPropertySet configuration;
public void SetProperties(IPropertySet configuration)
{
    this.configuration = configuration;
}
public double BlurAmount
{
    get
    {
        object val;
        if (configuration != null && configuration.TryGetValue("BlurAmount", out val))
        {
            return (double)val;
        }
        return 3;
    }
}

Der letzte Schritt besteht darin, die ProcessFrame-Methode zu implementieren, die die Bilddaten tatsächlich verarbeitet.The last step is to implement the ProcessFrame method that actually processes the image data.

Unter Verwendung von Win2D-APIs wird eine CanvasBitmap von der Direct3DSurface-Eigenschaft des Eingabeframes erstellt.Using Win2D APIs, a CanvasBitmap is created from the input frame's Direct3DSurface property. Ein CanvasRenderTarget wird von der Direct3DSurface des Ausgabeframes und eine CanvasDrawingSession von diesem Renderziel erstellt.A CanvasRenderTarget is created from the output frame's Direct3DSurface and a CanvasDrawingSession is created from this render target. Es wird ein neuer Win2D-GaussianBlurEffect initialisiert. Mithilfe der BlurAmount-Eigenschaft wird der Effekt über SetProperties bereitgestellt.A new Win2D GaussianBlurEffect is initialized, using the BlurAmount property our effect exposes via SetProperties. Schließlich wird die CanvasDrawingSession.DrawImage-Methode aufgerufen, um die Eingabebitmap mithilfe des Weichzeichnereffekts in das Renderziel zu ziehen.Finally, the CanvasDrawingSession.DrawImage method is called to draw the input bitmap to the render target using the blur effect.

public void ProcessFrame(ProcessVideoFrameContext context)
{

    using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromDirect3D11Surface(canvasDevice, context.InputFrame.Direct3DSurface))
    using (CanvasRenderTarget renderTarget = CanvasRenderTarget.CreateFromDirect3D11Surface(canvasDevice, context.OutputFrame.Direct3DSurface))
    using (CanvasDrawingSession ds = renderTarget.CreateDrawingSession())
    {


        var gaussianBlurEffect = new GaussianBlurEffect
        {
            Source = inputBitmap,
            BlurAmount = (float)BlurAmount,
            Optimization = EffectOptimization.Speed
        };

        ds.DrawImage(gaussianBlurEffect);

    }
}

Hinzufügen des benutzerdefinierten Effekts zu Ihrer AppAdding your custom effect to your app

Um den Videoeffekt aus Ihrer App zu verwenden, müssen Sie einen Verweis zum Effektprojekt zu Ihrer App hinzufügen.To use your video effect from your app, you must add a reference to the effect project to your app.

  1. Klicken Sie im Projektmappen-Explorer unter Ihrem App-Projekt mit der rechten Maustaste auf Verweise, und wählen Sie Verweis hinzufügen aus.In Solution Explorer, under your app project, right-click References and select Add reference.
  2. Erweitern Sie die Registerkarte Projekte, wählen Sie Projektmappe aus, und aktivieren Sie das Kontrollkästchen für den Projektnamen des Effekts.Expand the Projects tab, select Solution, and then select the check box for your effect project name. In diesem Beispiel lautet der Name videoeffectcomponent.For this example, the name is VideoEffectComponent.
  3. Klicken Sie auf OK.Click OK.

Hinzufügen Ihres benutzerdefinierten Effekts zu einem KameravideostreamAdd your custom effect to a camera video stream

Sie können einen einfachen Vorschaustream von der Kamera einrichten, indem Sie die Schritte im Artikel Einfacher Zugriff auf die Kameravorschau ausführen.You can set up a simple preview stream from the camera by following the steps in the article Simple camera preview access. Wenn Sie diese Schritte ausführen, erhalten Sie ein initialisiertes MediaCapture-Objekt, das für den Zugriff auf den Videostream der Kamera verwendet wird.Following those steps will provide you with an initialized MediaCapture object that is used to access the camera's video stream.

Um Ihren benutzerdefinierten Videoeffekt einem Kamerastream hinzuzufügen, erstellen Sie zuerst ein neues VideoEffectDefinition-Objekt, wobei der Namespace und der Klassenname für Ihren Effekt übergeben wird.To add your custom video effect to a camera stream, first create a new VideoEffectDefinition object, passing in the namespace and class name for your effect. Anschließend wird die addvideoeffect -Methode des mediacapture -Objekts aufgerufen, um den Effekt dem angegebenen Stream hinzuzufügen.Next, call the MediaCapture object's AddVideoEffect method to add your effect to the specified stream. In diesem Beispiel wird der MediaStreamType.VideoPreview-Wert verwendet, um anzugeben, dass der Effekt dem Vorschaustream hinzugefügt werden sollte.This example uses the MediaStreamType.VideoPreview value to specify that the effect should be added to the preview stream. Wenn Ihre App die Videoaufnahme unterstützt, könnten Sie auch MediaStreamType.VideoRecord verwenden, um den Effekt zum Aufnahmestream hinzuzufügen.If your app supports video capture, you could also use MediaStreamType.VideoRecord to add the effect to the capture stream. AddVideoEffect gibt ein IMediaExtension-Objekt zurück, das Ihren benutzerdefinierten Effekt darstellt.AddVideoEffect returns an IMediaExtension object representing your custom effect. Mit der SetProperties-Methode können Sie die Konfiguration für den Effekt festlegen.You can use the SetProperties method to set the configuration for your effect.

Nachdem der Effekt hinzugefügt wurde, wird StartPreviewAsync aufgerufen, um den Vorschaustream zu starten.After the effect has been added, StartPreviewAsync is called to start the preview stream.

var videoEffectDefinition = new VideoEffectDefinition("VideoEffectComponent.ExampleVideoEffect");

IMediaExtension videoEffect =
   await mediaCapture.AddVideoEffectAsync(videoEffectDefinition, MediaStreamType.VideoPreview);

videoEffect.SetProperties(new PropertySet() { { "FadeValue", .25 } });

await mediaCapture.StartPreviewAsync();

Hinzufügen Ihres benutzerdefinierten Effekts zu einem Clip in einer MediaCompositionAdd your custom effect to a clip in a MediaComposition

Allgemeine Informationen zum Erstellen von Medienkompositionen aus Videoclips finden Sie unter Medienkompositionen und -bearbeitung.For general guidance for creating media compositions from video clips, see Media compositions and editing. Der folgende Codeausschnitt zeigt das Erstellen einer einfachen Medienkomposition, die einen benutzerdefinierten Videoeffekt verwendet.The following code snippet shows the creation of a simple media composition that uses a custom video effect. Durch Aufruf von CreateFromFileAsync wird ein MediaClip-Objekt erstellt. Dabei wird eine Videodatei übergeben, die von dem Benutzer mit einer FileOpenPicker ausgewählt wurde, und der Clip wird zu einer neuen MediaComposition hinzugefügt.A MediaClip object is created by calling CreateFromFileAsync, passing in a video file that was selected by the user with a FileOpenPicker, and the clip is added to a new MediaComposition. Als Nächstes wird ein neues VideoEffectDefinition-Objekt erstellt, wobei der Namespace und der Klassenname für Ihren Effekt an den Konstruktor übergeben wird.Next a new VideoEffectDefinition object is created, passing in the namespace and class name for your effect to the constructor. Schließlich wird die Effektdefinition zur VideoEffectDefinitions-Sammlung des MediaClip-Objekts hinzugefügt.Finally, the effect definition is added to the VideoEffectDefinitions collection of the MediaClip object.

MediaComposition composition = new MediaComposition();
var clip = await MediaClip.CreateFromFileAsync(pickedFile);
composition.Clips.Add(clip);

var videoEffectDefinition = new VideoEffectDefinition("VideoEffectComponent.ExampleVideoEffect", new PropertySet() { { "FadeValue", .5 } });

clip.VideoEffectDefinitions.Add(videoEffectDefinition);