Tutorial: Livestreaming mit Media Services unter Verwendung von .NET 5.0

In Azure Media Services sind Liveereignisse für die Verarbeitung von Livestreaminginhalten zuständig. Bei einem Liveereignis wird ein Eingabeendpunkt (Erfassungs-URL) bereitgestellt, den Sie dann für einen Liveencoder bereitstellen. Das Liveereignis empfängt Eingabestreams aus dem Liveencoder und stellt diese zum Streamen über einen oder mehrere Streamingendpunkte zur Verfügung. Zudem stellen Liveereignisse einen Vorschauendpunkt (Vorschau-URL) bereit, mit dem Sie eine Vorschau des Streams anzeigen und überprüfen können, bevor Sie diesen weiter verarbeiten und übermitteln.

In diesem Tutorial erfahren Sie, wie Sie unter Verwendung von .NET 5.0 ein Liveereignis vom Typ Passthrough erstellen. In diesem Lernprogramm lernen Sie Folgendes:

Hinweis

Auch wenn in diesem Tutorial die .NET SDK-Beispiele verwendet werden, sind die allgemeinen Schritte für die REST-API, die CLI oder für andere unterstützte SDKs identisch.

Voraussetzungen

Für dieses Tutorial benötigen Sie Folgendes:

Sie benötigen diese zusätzlichen Elemente für Livestreamingsoftware:

  • Eine Kamera oder ein Gerät (beispielsweise ein Laptop) zum Übertragen eines Ereignisses.

  • Einen lokalen Softwareencoder, der Ihren Kameradatenstrom codiert und über das Real-Time Messaging Protocol (RTMP) an den Media Services-Livestreamingdienst sendet. Weitere Informationen finden Sie unter Empfohlene lokale Liveencoder. Der Datenstrom muss das Format RTMP oder Smooth Streaming haben.

    In diesem Beispiel wird davon ausgegangen, dass Sie OBS Studio (Open Broadcaster Software) verwenden, um RTMP an den Erfassungsendpunkt zu übertragen. Installieren Sie OBS Studio.

Tipp

Lesen Sie Livestreaming mit Azure Media Services v3, bevor Sie mit diesem Tutorial fortfahren.

Herunterladen und Konfigurieren des Beispiels

Klonen Sie mit dem folgenden Befehl das GitHub-Repository mit dem Beispiel für das Livestreaming mit .NET auf Ihren Computer:

git clone https://github.com/Azure-Samples/media-services-v3-dotnet.git

Das Livestreaming-Beispiel befindet sich im Ordner Live.

Öffnen Sie in Ihrem heruntergeladenen Projekt die Datei appsettings.json. Ersetzen Sie die Werte durch Anmeldeinformationen, die Sie durch den Zugriff auf APIs abgerufen haben.

Hinweis

Sie können auch das .env-Dateiformat im Stammverzeichnis des Projekts verwenden, um Ihre Umgebungsvariablen nur einmal für alle Projekte im .NET-Beispielrepository festzulegen. Kopieren Sie einfach die Datei sample.env, und geben Sie dann die Informationen an, die Sie im Azure-Portal über die Media Services-Seite für den API-Zugriff oder über die Azure CLI ermittelt haben. Benennen Sie die Datei sample.env in .env um, um sie in allen Projekten zu verwenden.

Die GITIGNORE-Datei ist bereits so konfiguriert, dass sie nicht in Ihrem geforkten Repository veröffentlicht wird.

Wichtig

In diesem Beispiel wird für jede Ressourcen ein eindeutiges Suffix verwendet. Wenn Sie das Debuggen abbrechen oder die App beenden, ohne das Beispiel vollständig zu durchlaufen, werden in Ihrem Konto mehrere Liveereignisse generiert.

Stellen Sie sicher, dass Sie die ausgeführten Liveereignisse beenden. Andernfalls fallen für die Ereignisse Kosten an!

Untersuchen des Codes für Livestreaming

In diesem Abschnitt werden Funktionen untersucht, die in den Dateien Authentication.cs (im Ordner „Common_Utils“) und Program.cs des Projekts LiveEventWithDVR definiert werden.

Das Beispiel erstellt für jede Ressource ein eindeutiges Suffix, damit keine Namenskonflikte auftreten, wenn Sie das Beispiel ohne Bereinigung der Ressourcen mehrmals ausführen.

Beginnen mit der Verwendung von Media Services-APIs mit dem .NET SDK

Mit „Authentication.cs“ wird unter Verwendung der Anmeldeinformationen aus den lokalen Konfigurationsdateien („appsettings.json“ oder „.env)“ ein AzureMediaServicesClient-Objekt erstellt.

Mit einem AzureMediaServicesClient-Objekt können Sie mit der Nutzung von Media Services-APIs mit .NET beginnen. Zum Erstellen des Objekts müssen Sie Anmeldeinformationen für den Client bereitstellen, damit dieser per Azure Active Directory eine Verbindung mit Azure herstellen kann. Dies wird in GetCredentialsAsync implementiert. Eine weitere Option ist die interaktive Authentifizierung, die in GetCredentialsInteractiveAuthAsync implementiert ist.

public static async Task<IAzureMediaServicesClient> CreateMediaServicesClientAsync(ConfigWrapper config, bool interactive = false)
{
    ServiceClientCredentials credentials;
    if (interactive)
        credentials = await GetCredentialsInteractiveAuthAsync(config);
    else
        credentials = await GetCredentialsAsync(config);

    return new AzureMediaServicesClient(config.ArmEndpoint, credentials)
    {
        SubscriptionId = config.SubscriptionId,
    };
}

Im Code, den Sie am Anfang des Artikels geklont haben, wird mit der Funktion GetCredentialsAsync das Objekt ServiceClientCredentials erstellt. Dies erfolgt basierend auf den Anmeldeinformationen in der lokalen Konfigurationsdatei (appsettings.json) oder über die Datei .env mit den Umgebungsvariablen im Stammverzeichnis des Repositorys.

private static async Task<ServiceClientCredentials> GetCredentialsAsync(ConfigWrapper config)
{
    // Use ConfidentialClientApplicationBuilder.AcquireTokenForClient to get a token using a service principal with symmetric key

    var scopes = new[] { config.ArmAadAudience + "/.default" };

    var app = ConfidentialClientApplicationBuilder.Create(config.AadClientId)
        .WithClientSecret(config.AadSecret)
        .WithAuthority(AzureCloudInstance.AzurePublic, config.AadTenantId)
        .Build();

    var authResult = await app.AcquireTokenForClient(scopes)
                                             .ExecuteAsync()
                                             .ConfigureAwait(false);

    return new TokenCredentials(authResult.AccessToken, TokenType);
}

Bei der interaktiven Authentifizierung wird durch die Funktion GetCredentialsInteractiveAuthAsync das Objekt ServiceClientCredentials erstellt, und zwar basierend auf einer interaktiven Authentifizierung und den Verbindungsparametern, die in der lokalen Konfigurationsdatei (appsettings.json) oder über die Umgebungsvariablendatei ( .env) im Stammverzeichnis des Repositorys angegeben sind. In diesem Fall sind „AADCLIENTID“ und „AADSECRET“ in der Konfigurations- oder Umgebungsvariablendatei nicht erforderlich.

private static async Task<ServiceClientCredentials> GetCredentialsInteractiveAuthAsync(ConfigWrapper config)
{
    var scopes = new[] { config.ArmAadAudience + "/user_impersonation" };

    // client application of Az Cli
    string ClientApplicationId = "04b07795-8ddb-461a-bbee-02f9e1bf7b46";

    AuthenticationResult result = null;

    IPublicClientApplication app = PublicClientApplicationBuilder.Create(ClientApplicationId)
        .WithAuthority(AzureCloudInstance.AzurePublic, config.AadTenantId)
        .WithRedirectUri("http://localhost")
        .Build();

    var accounts = await app.GetAccountsAsync();

    try
    {
        result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();
    }
    catch (MsalUiRequiredException)
    {
        try
        {
            result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
        }
        catch (MsalException maslException)
        {
            Console.Error.WriteLine($"ERROR: MSAL interactive authentication exception with code '{maslException.ErrorCode}' and message '{maslException.Message}'.");
        }
    }
    catch (MsalException maslException)
    {
        Console.Error.WriteLine($"ERROR: MSAL silent authentication exception with code '{maslException.ErrorCode}' and message '{maslException.Message}'.");
    }

    return new TokenCredentials(result.AccessToken, TokenType);
}

Erstellen eines Liveereignisses

In diesem Abschnitt wird das Erstellen eines Liveereignisses vom Typ Passthrough (LiveEventEncodingType auf None festgelegt) beschrieben. Weitere Informationen zu den verfügbaren Typen finden Sie unter Liveereignistypen. Zusätzlich zu Passthrough können Sie ein Ereignis mit Livetranscodierung für eine Cloudcodierung mit adaptiver Bitrate (720p oder 1080p) verwenden.

Beim Erstellen des Liveereignisses können Sie beispielsweise Folgendes angeben:

  • Erfassungsprotokoll für das Liveereignis: Derzeit werden die Protokolle RTMP, RTMPS und Smooth Streaming unterstützt. Die Protokolloption kann nicht geändert werden, während das Liveereignis oder die zugehörigen Liveausgaben aktiv sind. Sollten Sie verschiedene Protokolle benötigen, erstellen Sie für jedes Streamingprotokoll ein separates Liveereignis.

  • IP-Einschränkungen für Erfassung und Vorschau: Sie können die IP-Adressen definieren, die ein Video für dieses Liveereignis erfassen dürfen. Zulässige IP-Adressen können als eine der folgenden Optionen angegeben werden:

    • Einzelne IP-Adresse (z. B. 10.0.0.1)
    • Ein IP-Adressbereich, für den eine IP-Adresse und eine CIDR-Subnetzmaske (Classless Inter-Domain Routing) verwendet werden (z. B. 10.0.0.1/22)
    • Ein IP-Adressbereich, für den eine IP-Adresse und Subnetzmaske in Dezimalschreibweise mit Punkten (z. B. 10.0.0.1(255.255.252.0)) verwendet werden

    Wenn keine IP-Adressen angegeben sind und es keine Regeldefinition gibt, sind keine IP-Adressen zulässig. Erstellen Sie eine Regel, und geben Sie 0.0.0.0/0 an, um alle IP-Adressen zuzulassen. Die IP-Adressen müssen in einem der folgenden Formate vorliegen: IPv4-Adresse mit vier Ziffern oder CIDR-Adressbereich.

  • Autostart für ein Ereignis, während Sie es erstellen: Wenn für den automatischen Start true festgelegt ist, wird das Liveereignis nach der Erstellung gestartet. Dies bedeutet, dass die Abrechnung beginnt, sobald die Ausführung des Liveereignisses startet. Sie müssen für die Liveereignisressource explizit Stop auswählen, damit keine weiteren Gebühren anfallen. Weitere Informationen finden Sie unter Zustandswerte von Liveereignissen und Abrechnung.

    Standbymodi sind verfügbar, um das Liveereignis in einem kostengünstigeren „zugeordneten“ Zustand zu starten, der den Wechsel in einen Ausführungszustand beschleunigt. Dies ist etwa im Falle von Pools der heißen Ebene hilfreich, die schnell Kanäle für Streamer bereitstellen müssen.

  • Ein statischer Hostname und eine eindeutige GUID: Legen Sie die Eigenschaft useStaticHostname auf true fest, um eine vorhersagbare Erfassungs-URL zu erhalten, die zudem einfacher in einem hardwarebasierten Liveencoder verwaltet werden kann. Ausführliche Informationen finden Sie unter Erfassungs-URLs für Liveereignisse.

Console.WriteLine($"Creating a live event named {liveEventName}");
Console.WriteLine();

// Creating the LiveEvent - the primary object for live streaming in AMS. 
// See the overview - https://docs.microsoft.com/azure/media-services/latest/live-streaming-overview

// Create the LiveEvent

// Understand the concepts of what a live event and a live output is in AMS first!
// Read the following - https://docs.microsoft.com/azure/media-services/latest/live-events-outputs-concept
// 1) Understand the billing implications for the various states
// 2) Understand the different live event types, pass-through and encoding
// 3) Understand how to use long-running async operations 
// 4) Understand the available Standby mode and how it differs from the Running Mode. 
// 5) Understand the differences between a LiveOutput and the Asset that it records to.  They are two different concepts.
//    A live output can be considered as the "tape recorder" and the Asset is the tape that is inserted into it for recording.
// 6) Understand the advanced options such as low latency, and live transcription/captioning support. 
//    Live Transcription - https://docs.microsoft.com/en-us/azure/media-services/latest/live-transcription
//    Low Latency - https://docs.microsoft.com/en-us/azure/media-services/latest/live-event-latency

// When broadcasting to a live event, please use one of the verified on-premises live streaming encoders.
// While operating this tutorial, it is recommended to start out using OBS Studio before moving to another encoder. 

// Note: When creating a LiveEvent, you can specify allowed IP addresses in one of the following formats:                 
//      IpV4 address with 4 numbers
//      CIDR address range  

IPRange allAllowIPRange = new(
    name: "AllowAll",
    address: "0.0.0.0",
    subnetPrefixLength: 0
);

// Create the LiveEvent input IP access control object
// this will control the IP that the encoder is running on and restrict access to only that encoder IP range.
LiveEventInputAccessControl liveEventInputAccess = new()
{
    Ip = new IPAccessControl(
            allow: new IPRange[]
            {
                // re-use the same range here for the sample, but in production you can lock this
                // down to the ip range for your on-premises live encoder, laptop, or device that is sending
                // the live stream
                allAllowIPRange
            }
        )

};

// Create the LiveEvent Preview IP access control object. 
// This will restrict which clients can view the preview endpoint
LiveEventPreview liveEventPreview = new()
{
    AccessControl = new LiveEventPreviewAccessControl(
        ip: new IPAccessControl(
            allow: new IPRange[]
            {
                 // re-use the same range here for the sample, but in production you can lock this to the IPs of your 
                // devices that would be monitoring the live preview. 
                allAllowIPRange
            }
        )
    )
};

// To get the same ingest URL for the same LiveEvent name:
// 1. Set useStaticHostname to true so you have ingest like: 
//        rtmps://liveevent-hevc12-eventgridmediaservice-usw22.channel.media.azure.net:2935/live/522f9b27dd2d4b26aeb9ef8ab96c5c77           
// 2. Set the inputs:accessToken to a desired GUID string (with or without hyphen) to make it simpler to update your encoder settings

// See REST API documentation for details on each setting value
// https://docs.microsoft.com/rest/api/media/liveevents/create 

LiveEvent liveEvent = new(
    location: mediaService.Location,
    description: "Sample LiveEvent from .NET SDK sample",
    // Set useStaticHostname to true to make the ingest and preview URL host name the same. 
    // This can slow things down a bit. 
    useStaticHostname: true,

    // 1) Set up the input settings for the Live event...
    input: new LiveEventInput(
        streamingProtocol: LiveEventInputProtocol.RTMP,  // options are RTMP or Smooth Streaming ingest format.
                                                         // This sets a static access token for use on the ingest path. 
                                                         // Combining this with useStaticHostname:true will give you the same ingest URL on every creation.
                                                         // This is helpful when you only want to enter the URL into a single encoder one time for this Live Event name
        accessToken: "acf7b6ef-8a37-425f-b8fc-51c2d6a5a86a",  // Use this value when you want to make sure the ingest URL is static and always the same. If omitted, the service will generate a random GUID value.
        accessControl: liveEventInputAccess, // controls the IP restriction for the source encoder.
        keyFrameIntervalDuration: "PT2S" // Set this to match the ingest encoder's settings
    ),
    // 2) Set the live event to use pass-through or cloud encoding modes...
    encoding: new LiveEventEncoding(
        // Set this to Standard (720P) or Premium1080P to use the cloud live encoder.
        // See https://go.microsoft.com/fwlink/?linkid=2095101 for more information
        // Otherwise, set to PassthroughBasic or PassthroughStandard to use the two different pass-through modes. 
        encodingType: LiveEventEncodingType.PassthroughStandard // Choose the type of live event - standard or basic pass-through, or the encoding types for 720P or 1080P
                                                                // OPTIONAL settings when using live cloud encoding type:
                                                                // keyFrameInterval: "PT2S", //If this value is not set for an encoding live event, the fragment duration defaults to 2 seconds. The value cannot be set for pass-through live events.
                                                                // presetName: null, // only used for custom defined presets. 
                                                                //stretchMode: "None" // can be used to determine stretch on encoder mode
    ),
    // 3) Set up the Preview endpoint for monitoring based on the settings above we already set.
    preview: liveEventPreview,
    // 4) Set up more advanced options on the live event. Low Latency is the most common one.
    streamOptions: new List<StreamOptionsFlag?>()
    {
        // Set this to Default or Low Latency
        // When using Low Latency mode, you must configure the Azure Media Player to use the 
        // quick start heuristic profile or you won't notice the change. 
        // In the AMP player client side JS options, set -  heuristicProfile: "Low Latency Heuristic Profile". 
        // To use low latency optimally, you should tune your encoder settings down to 1 second GOP size instead of 2 seconds.
        StreamOptionsFlag.LowLatency
    }
//,
// 5) Optionally enable live transcriptions if desired. This is only supported on PassthroughStandard, and the transcoding live event types. It is not supported on Basic pass-through type.
// WARNING : This is extra cost ($$$), so please check pricing before enabling.
/*transcriptions:new List<LiveEventTranscription>(){
    new LiveEventTranscription(
        // The value should be in BCP-47 format (e.g: 'en-US'). See https://go.microsoft.com/fwlink/?linkid=2133742
        language: "en-us",
        outputTranscriptionTrack : new LiveEventOutputTranscriptionTrack(
            trackName: "English" // set the name you want to appear in the output manifest
        )
    )
}*/
);

// Start monitoring LiveEvent events using Event Grid and Event Hub
try
{
    // Please refer README for Event Hub and storage settings.
    // A storage account is required to process the Event Hub events from the Event Grid subscription in this sample.

    // Create a new host to process events from an Event Hub.
    Console.WriteLine("Creating a new client to process events from an Event Hub...");
    var credential = new DefaultAzureCredential();
    var storageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
       config.StorageAccountName, config.StorageAccountKey);
    var blobContainerName = config.StorageContainerName;
    var eventHubsConnectionString = config.EventHubConnectionString;
    var eventHubName = config.EventHubName;
    var consumerGroup = config.EventHubConsumerGroup;

    storageClient = new BlobContainerClient(
        storageConnectionString,
        blobContainerName);

    processorClient = new EventProcessorClient(
        storageClient,
        consumerGroup,
        eventHubsConnectionString,
        eventHubName);

    mediaEventProcessor = new MediaServicesEventProcessor(null, null, liveEventName);
    processorClient.ProcessEventAsync += mediaEventProcessor.ProcessEventsAsync;
    processorClient.ProcessErrorAsync += mediaEventProcessor.ProcessErrorAsync;

    await processorClient.StartProcessingAsync();
}
catch (Exception e)
{
    Console.WriteLine("Failed to connect to Event Hub, please refer README for Event Hub and storage settings. Skipping event monitoring...");
    Console.WriteLine(e.Message);
}

Console.WriteLine("Creating the LiveEvent, please be patient as this can take time to complete async.");
Console.WriteLine("Live Event creation is an async operation in Azure and timing can depend on resources available.");

// When autostart is set to true, the Live Event will be started after creation. 
// That means, the billing starts as soon as the Live Event starts running. 
// You must explicitly call Stop on the Live Event resource to halt further billing.
// The following operation can sometimes take awhile. Be patient.
// On optional workflow is to first call allocate() instead of create. 
// https://docs.microsoft.com/en-us/rest/api/media/liveevents/allocate 
// This allows you to allocate the resources and place the live event into a "Standby" mode until 
// you are ready to transition to "Running". This is useful when you want to pool resources in a warm "Standby" state at a reduced cost.
// The transition from Standby to "Running" is much faster than cold creation to "Running" using the autostart property.
// Returns a long running operation polling object that can be used to poll until completion.

Stopwatch watch = Stopwatch.StartNew();
liveEvent = await client.LiveEvents.CreateAsync(
    config.ResourceGroup,
    config.AccountName,
    liveEventName,
    liveEvent,
    // When autostart is set to true, you should "await" this method operation to complete. 
    // The Live Event will be started after creation. 
    // You may choose not to do this, but create the object, and then start it using the standby state to 
    // keep the resources "warm" and billing at a lower cost until you are ready to go live. 
    // That increases the speed of startup when you are ready to go live. 
    autoStart: false);
watch.Stop();
string elapsedTime = String.Format(":{0:00}.{1:00}", watch.Elapsed.Seconds, watch.Elapsed.Milliseconds / 10);
Console.WriteLine($"Create Live Event run time : {elapsedTime}");

Abrufen von Erfassungs-URLs

Nachdem das Liveereignis erstellt wurde, können Sie Erfassungs-URLs abrufen, um diese für den Liveencoder bereitzustellen. Diese URLs werden vom Encoder zur Eingabe eines Livedatenstroms verwendet.

// Get the RTMP ingest URL to configure in OBS Studio. 
// The endpoints is a collection of RTMP primary and secondary, and RTMPS primary and secondary URLs. 
// to get the primary secure RTMPS, it is usually going to be index 3, but you could add a loop here to confirm...
string ingestUrl = liveEvent.Input.Endpoints.First().Url;
Console.WriteLine($"The RTMP ingest URL to enter into OBS Studio is:");
Console.WriteLine($"\t{ingestUrl}");
Console.WriteLine("Make sure to enter a Stream Key into the OBS studio settings. It can be any value or you can repeat the accessToken used in the ingest URL path.");
Console.WriteLine();

Abrufen der Vorschau-URL

Rufen Sie mit previewEndpoint die Vorschau-URL ab, und überprüfen Sie, ob die Eingabe des Encoders empfangen wird.

Wichtig

Vergewissern Sie sich vor dem Fortfahren, dass das Video an die Vorschau-URL übertragen wird.

// Use the previewEndpoint to preview and verify
// that the input from the encoder is actually being received
// The preview endpoint URL also support the addition of various format strings for HLS (format=m3u8-cmaf) and DASH (format=mpd-time-cmaf) for example.
// The default manifest is Smooth. 
string previewEndpoint = liveEvent.Preview.Endpoints.First().Url;
Console.WriteLine($"The preview url is:");
Console.WriteLine($"\t{previewEndpoint}");
Console.WriteLine();

Console.WriteLine($"Open the live preview in your browser and use the Azure Media Player to monitor the preview playback:");
Console.WriteLine($"\thttps://ampdemo.azureedge.net/?url={previewEndpoint}&heuristicprofile=lowlatency");
Console.WriteLine();

Erstellen und Verwalten von Liveereignissen und Liveausgaben

Sobald der Stream an das Liveereignis übertragen wird, können Sie das Streamingereignis starten, indem Sie ein Medienobjekt, eine Liveausgabe und einen Streaminglocator erstellen. Dadurch wird der Datenstrom archiviert und über den Streamingendpunkt für die Zuschauer verfügbar gemacht.

Beim Erlernen dieser Konzepte ist es hilfreich, wenn Sie sich dieses Medienobjekt als „Videokassette“ vorstellen, wie sie früher einmal in einen Videorekorder eingelegt wurde. Die Liveausgabe fungiert hierbei als „Videorekorder“. Das Liveereignis ist das vom Videorekorder ausgegebene Videosignal.

Als Erstes erstellen Sie das Signal, indem Sie das Liveereignis erstellen. Das Signal wird erst übertragen, wenn Sie dieses Liveereignis starten und Ihren Encoder mit der Eingabe verbinden.

Die Videokassette kann zu einem beliebigen Zeitpunkt erstellt werden. Sie stellt lediglich ein leeres Medienobjekt dar, das an das Objekt für die Liveausgabe (in dieser Analogie: der Videorekorder) übergeben wird.

Der Videorekorder kann ebenfalls zu einem beliebigen Zeitpunkt erstellt werden. Sie können eine Liveausgabe vor oder nach dem Starten der Signalübertragung erstellen. Wenn es schnell gehen muss, kann es hilfreich sein, die Ausgabe vor dem Starten der Signalübertragung zu erstellen.

Um die „Videoaufnahme“ zu beenden, rufen Sie delete für LiveOutput auf. Mit dieser Aktion wird der Inhalt auf dem „Video“ (Medienobjekt) nicht gelöscht. Das Medienobjekt bleibt zusammen mit dem archivierten Videoinhalt erhalten, bis Sie direkt für das Medienobjekt explizit delete aufrufen.

Im nächsten Abschnitt wird die Erstellung des Medienobjekts und der Liveausgabe Schritt für Schritt beschrieben.

Erstellen eines Medienobjekts

Erstellen Sie ein Medienobjekt, das von der Liveausgabe verwendet werden kann. Im Rahmen unserer Analogie ist dies die Videokassette zum Aufzeichnen des Livevideosignals. Benutzer können sich den Inhalt live oder bedarfsgesteuert (On-Demand) über diese virtuelle Videokassette ansehen.

// Create an Asset for the LiveOutput to use. Think of this as the "tape" that will be recorded to. 
// The asset entity points to a folder/container in your Azure Storage account. 
Console.WriteLine($"Creating an asset named {assetName}");
Console.WriteLine();
Asset asset = await client.Assets.CreateOrUpdateAsync(config.ResourceGroup, config.AccountName, assetName, new Asset());

Erstellen einer Liveausgabe

Liveausgaben beginnen, wenn sie erstellt werden, und enden, wenn sie gelöscht werden. Wenn Sie die Liveausgabe löschen, bleiben das zugrunde liegende Medienobjekt und dessen Inhalt erhalten. Stellen Sie sich dies als Auswerfen des „Bands“ vor. Das Medienobjekt mit der Aufzeichnung bleibt so lange gespeichert, wie Sie möchten. Wenn es ausgeworfen wird (Löschen der Liveausgabe), ist es sofort für die bedarfsgesteuerte Anzeige verfügbar.

// Create the Live Output - think of this as the "tape recorder for the live event". 
// Live outputs are optional, but are required if you want to archive the event to storage,
// use the asset for on-demand playback later, or if you want to enable cloud DVR time-shifting.
// We will use the asset created above for the "tape" to record to. 
string manifestName = "output";
Console.WriteLine($"Creating a live output named {liveOutputName}");
Console.WriteLine();

watch = Stopwatch.StartNew();
// See the REST API for details on each of the settings on Live Output
// https://docs.microsoft.com/rest/api/media/liveoutputs/create
LiveOutput liveOutput = new(
    assetName: asset.Name,
    manifestName: manifestName, // The HLS and DASH manifest file name. This is recommended to set if you want a deterministic manifest path up front.
                                // archive window can be set from 3 minutes to 25 hours. Content that falls outside of ArchiveWindowLength
                                // is continuously discarded from storage and is non-recoverable. For a full event archive, set to the maximum, 25 hours.
    archiveWindowLength: TimeSpan.FromHours(1)
);
liveOutput = await client.LiveOutputs.CreateAsync(
    config.ResourceGroup,
    config.AccountName,
    liveEventName,
    liveOutputName,
    liveOutput);
elapsedTime = String.Format(":{0:00}.{1:00}", watch.Elapsed.Seconds, watch.Elapsed.Milliseconds / 10);
Console.WriteLine($"Create Live Output run time : {elapsedTime}");
Console.WriteLine();

Erstellen Sie eines Streaminglocators

Hinweis

Beim Erstellen Ihres Media Services-Kontos wird dem Konto ein Standard-Streamingendpunkt im Zustand „Beendet“ hinzugefügt. Um mit dem Streamen Ihrer Inhalte zu beginnen und die dynamische Paketerstellung und dynamische Verschlüsselung zu nutzen, muss sich der Streamingendpunkt, von dem Sie Inhalte streamen möchten, im Zustand „Wird ausgeführt“ befinden.

Wenn Sie das Medienobjekt mit einem Streaminglocator veröffentlichen, kann das Liveereignis (maximal bis zur DVR-Fensterlänge) bis zum Ablaufen oder Löschen des Streaminglocators (je nachdem, was zuerst eintritt) weiterhin angezeigt werden. Auf diese Weise können Sie die virtuelle Aufzeichnung so verfügbar machen, dass sie von Ihrer Zielgruppe live und „On-Demand“ angesehen werden kann. Über dieselbe URL kann das Liveereignis, das DVR-Fenster oder das On-Demand-Medienobjekt angesehen werden, nachdem die Aufzeichnung abgeschlossen ist (nach dem Löschen der Liveausgabe).

Console.WriteLine($"Creating a streaming locator named {streamingLocatorName}");
Console.WriteLine();

IList<string> filters = new List<string>
{
    drvAssetFilterName
};
StreamingLocator locator = await client.StreamingLocators.CreateAsync(config.ResourceGroup,
    config.AccountName,
    drvStreamingLocatorName,
    new StreamingLocator
    {
        AssetName = assetName,
        StreamingPolicyName = PredefinedStreamingPolicy.ClearStreamingOnly,
        Filters = filters   // Associate the dvr filter with StreamingLocator.
    });

// Get the default Streaming Endpoint on the account
StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(config.ResourceGroup, config.AccountName, streamingEndpointName);

// If it's not running, Start it. 
if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running)
{
    Console.WriteLine("Streaming Endpoint was Stopped, restarting now..");
    await client.StreamingEndpoints.StartAsync(config.ResourceGroup, config.AccountName, streamingEndpointName);

    // Since we started the endpoint, we should stop it in cleanup.
    stopEndpoint = true;
}

// Get the URL to stream the output
ListPathsResponse paths = await client.StreamingLocators.ListPathsAsync(resourceGroupName, accountName, locatorName);

foreach (StreamingPath path in paths.StreamingPaths)
{
    UriBuilder uriBuilder = new UriBuilder();
    uriBuilder.Scheme = "https";
    uriBuilder.Host = streamingEndpoint.HostName;

    uriBuilder.Path = path.Paths[0];
    // Get the URL from the uriBuilder: uriBuilder.ToString()
}

Bereinigen von Ressourcen in Ihrem Media Services-Konto

Verwenden Sie das folgende Verfahren, wenn die Streamingereignisse beendet sind und Sie die zuvor bereitgestellten Ressourcen bereinigen möchten:

  1. Beenden Sie die Datenstromeingabe vom Encoder.
  2. Beenden Sie das Liveereignis. Nach Beendigung des Liveereignisses fallen dafür keine weiteren Kosten an. Wenn Sie den Kanal erneut starten, weist er die gleiche Erfassungs-URL auf, damit Sie den Encoder nicht erneut konfigurieren müssen.
  3. Beenden Sie Ihren Streamingendpunkt, sofern Sie das Archiv Ihres Liveereignisses nicht als bedarfsgesteuerten Datenstrom bereitstellen möchten. Wenn sich das Liveereignis im Zustand „Beendet“ befindet, fallen dafür keine weiteren Kosten an.
private static async Task CleanupLiveEventAndOutputAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string liveEventName, string liveOutputName)
{
    try
    {
        LiveEvent liveEvent = await client.LiveEvents.GetAsync(resourceGroup, accountName, liveEventName);

        Console.WriteLine("Deleting Live Output");
        Stopwatch watch = Stopwatch.StartNew();

        await client.LiveOutputs.DeleteAsync(resourceGroup, accountName, liveEventName, liveOutputName);

        String elapsedTime = String.Format(":{0:00}.{1:00}", watch.Elapsed.Seconds, watch.Elapsed.Milliseconds / 10);
        Console.WriteLine($"Delete Live Output run time : {elapsedTime}");

        if (liveEvent != null)
        {
            if (liveEvent.ResourceState == LiveEventResourceState.Running)
            {
                watch = Stopwatch.StartNew();
                // If the LiveEvent is running, stop it and have it remove any LiveOutputs
                await client.LiveEvents.StopAsync(resourceGroup, accountName, liveEventName, removeOutputsOnStop: false);
                elapsedTime = String.Format(":{0:00}.{1:00}", watch.Elapsed.Seconds, watch.Elapsed.Milliseconds / 10);
                Console.WriteLine($"Stop Live Event run time : {elapsedTime}");
            }

            // Delete the LiveEvent
            await client.LiveEvents.DeleteAsync(resourceGroup, accountName, liveEventName);
        }
    }
    catch (ErrorResponseException e)
    {
        Console.WriteLine("CleanupLiveEventAndOutputAsync -- Hit ErrorResponseException");
        Console.WriteLine($"\tCode: {e.Body.Error.Code}");
        Console.WriteLine($"\tCode: {e.Body.Error.Message}");
        Console.WriteLine();
    }
}
private static async Task CleanupLocatorandAssetAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string streamingLocatorName, string assetName)
{
    try
    {
        // Delete the Streaming Locator
        await client.StreamingLocators.DeleteAsync(resourceGroup, accountName, streamingLocatorName);

        // Delete the Archive Asset
        await client.Assets.DeleteAsync(resourceGroup, accountName, assetName);
    }
    catch (ErrorResponseException e)
    {
        Console.WriteLine("CleanupLocatorandAssetAsync -- Hit ErrorResponseException");
        Console.WriteLine($"\tCode: {e.Body.Error.Code}");
        Console.WriteLine($"\tCode: {e.Body.Error.Message}");
        Console.WriteLine();
    }
}

Ansehen des Ereignisses

Drücken Sie STRG+F5, um den Code auszuführen. Dadurch werden Streaming-URLs ausgegeben, die Sie zum Ansehen Ihres Liveereignisses verwenden können. Kopieren Sie die Streaming-URL, die Sie zum Erstellen eines Streaminglocators erhalten haben. Sie können einen Medienplayer Ihrer Wahl verwenden. Azure Media Player ist verfügbar, um Ihren Datenstrom auf der Media Player-Demowebsite zu testen.

Für ein Liveereignis werden Ereignisse bei der Beendigung automatisch in On-Demand-Inhalte konvertiert. Auch nach dem Beenden und Löschen des Ereignisses können die Benutzer archivierte Inhalte als Video auf Abruf streamen, solange Sie das Medienobjekt nicht löschen. Ein Medienobjekt kann nicht gelöscht werden, wenn es von einem Ereignis verwendet wird. Zuerst muss das betreffende Ereignis gelöscht werden.

Bereinigen der restlichen Ressourcen

Wenn Sie keine Ressourcen in Ihrer Ressourcengruppe mehr benötigen, einschließlich der Media Services und Speicherkonten, die Sie für dieses Tutorial erstellt haben, sollten Sie die zuvor erstellte Ressourcengruppe löschen.

Führen Sie den folgenden CLI-Befehl aus:

az group delete --name amsResourceGroup

Wichtig

Wenn Sie das Liveereignis nicht beenden, fallen weiter Kosten dafür an. Beachten Sie, dass das Liveereignis möglicherweise im Abrechnungszustand verbleibt, wenn das Projekt oder Programm nicht mehr reagiert oder aufgrund eines anderen Problems geschlossen wird.