Zelfstudie: Video's analyseren met Media Services v3

media services logo v3


Zoekt u Media Services v2-documentatie?

In deze zelfstudie ziet u hoe u video's kunt analyseren met Azure Media Services. Er zijn veel scenario's waarin u misschien inzicht wilt krijgen in opgenomen video's of audio-inhoud. Voor het bereiken van een hogere klanttevredenheid kunnen organisaties bijvoorbeeld spraak-naar-tekstverwerking uitvoeren om opnamen van de klantenondersteuning om te zetten in een catalogus van zoekmachines, met indexen en dashboards.

In deze zelfstudie ontdekt u hoe u:

  • Download de voorbeeld-app, zoals beschreven in het onderwerp.
  • De code kunt onderzoeken waarmee de opgegeven video wordt geanalyseerd.
  • Voer de app uit.
  • De uitvoer kunt onderzoeken.
  • Resources opschonen.

Als u geen Azure-abonnement hebt, maakt u een gratis account voordat u begint.

Naleving, privacy en beveiliging

Als belangrijke herinnering moet u voldoen aan alle toepasselijke wetten in uw gebruik van Azure Video Analyzer for Media (voorheen Video Indexer). U mag Video Analyzer voor Media of een andere Azure-service niet gebruiken op een manier die de rechten van anderen schendt. Voordat u video's, inclusief biometrische gegevens, uploadt naar de Video Analyzer for Media-service voor verwerking en opslag, moet u alle juiste rechten hebben, inclusief alle juiste toestemmingen van de personen in de video. Voor meer informatie over naleving, privacy en beveiliging in Video Analyzer for Media, de Azure Cognitive Services Terms. Voor de privacyverplichtingen van Microsoft en de verwerking van uw gegevens, bekijkt u de privacyverklaringvan Microsoft, de Voorwaarden voor Online Diensten (OST) en de aanvulling op gegevensverwerking ('DPA'). Meer privacy-informatie, waaronder over gegevensretentie, verwijdering/vernietigen, is beschikbaar in de OST en hier. Door Video Analyzer voor Media te gebruiken, gaat u ermee akkoord dat u bent gebonden aan de Cognitive Services voorwaarden, de OST, DPA en de privacyverklaring.

Vereisten

Het voorbeeld downloaden en configureren

Kloon met de volgende opdracht een GitHub-opslagplaats met het .NET-voorbeeld op de computer:

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

Het voorbeeld bevindt zich in de map AnalyzeVideos.

Open appsettings.json in het project dat u hebt gedownload. Vervang de waarden door referenties die u hebt verkregen via toegang tot API's.

Notitie

U kunt ook de bestandsindeling .env in de hoofdmap van het project gebruiken om uw omgevingsvariabelen slechts één keer in te stellen voor alle projecten in de opslagplaats met .NET-voorbeelden. Kopieer het bestand sample.env en vul vervolgens de gegevens in die u hebt ontvangen van de Media Services API-toegangspagina in het Azure Portal of de Azure CLI. Wijzig de naam van het bestand sample.env in alleen .env om het in alle projecten te gebruiken.

Het bestand .gitignore is al geconfigureerd om te voorkomen dat dit bestand naar uw gevorkte opslagplaats wordt gepubliceerd.

De code onderzoeken die de opgegeven video analyseert

In dit gedeelte worden de functies bekeken die zijn gedefinieerd in het bestand Program.cs van het project AnalyzeVideos.

Door het voorbeeld worden de volgende acties voltooid:

  1. Een Transformatie en een Taak maken voor het analyseren van de video.
  2. Een invoer asset maken en de video uploaden naar deze asset. De asset wordt gebruikt als de invoer voor de taak.
  3. Een uitvoerasset maken waarin de uitvoer van de taak wordt opgeslagen.
  4. De taak verzenden.
  5. De status van de taak controleren.
  6. De bestanden downloaden die het resultaat zijn van het uitvoeren van de taak.

Aan de slag Media Services API's met de .NET SDK

Als u Media Services api's met .NET wilt gaan gebruiken, moet u een AzureMediaServicesClient -object maken. Als u het object wilt maken, moet u referenties voor de client leveren om verbinding te maken met Azure met behulp van Azure Active Directory. Een andere optie is het gebruik van interactieve verificatie, die is geïmplementeerd in GetCredentialsInteractiveAuthAsync .

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

In de code die u aan het begin van het artikel hebt gekloond, maakt de functie het object op basis van de referenties die zijn opgegeven in het lokale configuratiebestand GetCredentialsAsync ServiceClientCredentials (appsettings.json) of via het bestand met omgevingsvariabelen .env in de hoofdmap van de opslagplaats.

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

In het geval van interactieve verificatie maakt de functie het object op basis van een interactieve verificatie en de verbindingsparameters die zijn opgegeven in het lokale configuratiebestand GetCredentialsInteractiveAuthAsync ServiceClientCredentials (appsettings.json) of via het bestand met omgevingsvariabelen .env in de hoofdmap van de opslagplaats. In dat geval zijn AADCLIENTID en AADSECRET niet nodig in het bestand met configuratie- of omgevingsvariabelen.

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 ex)
    {
        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);
}

Een invoerasset maken en er een lokaal bestand in uploaden

Met de functie CreateInputAsset wordt een nieuwe invoerasset gemaakt en het opgegeven lokale videobestand wordt hierin geladen. Deze asset wordt gebruikt als invoer voor uw coderingstaak. In Media Services-v3 kan de invoer voor een taak een asset zijn of inhoud die u beschikbaar maakt voor uw Media Services-account via HTTPS-URL's. Zie dit artikel als u wilt weten hoe u een HTTPS-URL kunt coderen.

In Media Services v3 kunt u Azure Storage-API's gebruiken om bestanden te uploaden. Het volgende .NET-fragment laat zien hoe.

Met de volgende functie worden de volgende acties voltooid:

  • Er wordt een asset gemaakt.

  • Er wordt een schrijfbare SAS-URL opgehaald voor de container in opslag van de asset.

    Als u de functie ListContainerSas van de asset gebruikt om SAS-URL's op te halen, moet u er rekening mee houden dat met deze functie meerdere SAS-URL's worden geretourneerd, aangezien er voor elk opslagaccount twee opslagaccountsleutels zijn. Een opslagaccount heeft twee sleutels omdat dit naadloze rotatie van opslagaccountsleutels mogelijk maakt (bijvoorbeeld als u een van de sleutels wilt wijzigen terwijl u de andere gebruikt en vervolgens de nieuwe sleutel wilt gebruiken en de andere roteert). De eerste SAS-URL staat voor opslagsleutel 1 en een tweede voor opslagsleutel 2.

  • Uploadt het bestand naar de container in opslag met behulp van de SAS-URL.

private static async Task<Asset> CreateInputAssetAsync(
    IAzureMediaServicesClient client,
    string resourceGroupName,
    string accountName,
    string assetName,
    string fileToUpload)
{
    // In this example, we are assuming that the asset name is unique.
    //
    // If you already have an asset with the desired name, use the Assets.Get method
    // to get the existing asset. In Media Services v3, the Get method on entities returns null 
    // if the entity doesn't exist (a case-insensitive check on the name).

    // Call Media Services API to create an Asset.
    // This method creates a container in storage for the Asset.
    // The files (blobs) associated with the asset will be stored in this container.
    Asset asset = await client.Assets.CreateOrUpdateAsync(resourceGroupName, accountName, assetName, new Asset());

    // Use Media Services API to get back a response that contains
    // SAS URL for the Asset container into which to upload blobs.
    // That is where you would specify read-write permissions 
    // and the exparation time for the SAS URL.
    var response = await client.Assets.ListContainerSasAsync(
        resourceGroupName,
        accountName,
        assetName,
        permissions: AssetContainerPermission.ReadWrite,
        expiryTime: DateTime.UtcNow.AddHours(4).ToUniversalTime());

    var sasUri = new Uri(response.AssetContainerSasUrls.First());

    // Use Storage API to get a reference to the Asset container
    // that was created by calling Asset's CreateOrUpdate method.  
    BlobContainerClient container = new BlobContainerClient(sasUri);
    BlobClient blob = container.GetBlobClient(Path.GetFileName(fileToUpload));

    // Use Storage API to upload the file into the container in storage.
    await blob.UploadAsync(fileToUpload);

    return asset;
}

Een uitvoerasset maken voor het opslaan van het resultaat van de taak

In de uitvoerasset wordt het resultaat van de taak opgeslagen. Het project definieert de functie DownloadResults die de resultaten van deze uitvoerasset naar de uitvoermap downloadt zodat u kunt zien wat u hebt gekregen.

private static async Task<Asset> CreateOutputAssetAsync(IAzureMediaServicesClient client, string resourceGroupName, string accountName, string assetName)
{
    bool existingAsset = true;
    Asset outputAsset;
    try
    {
        // Check if an Asset already exists
        outputAsset = await client.Assets.GetAsync(resourceGroupName, accountName, assetName);
    }
    catch (ErrorResponseException ex) when (ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
    {
        existingAsset = false;
    }

    Asset asset = new Asset();
    string outputAssetName = assetName;

    if (existingAsset)
    {
        // Name collision! In order to get the sample to work, let's just go ahead and create a unique asset name
        // Note that the returned Asset can have a different name than the one specified as an input parameter.
        // You may want to update this part to throw an Exception instead, and handle name collisions differently.
        string uniqueness = $"-{Guid.NewGuid():N}";
        outputAssetName += uniqueness;

        Console.WriteLine("Warning – found an existing Asset with name = " + assetName);
        Console.WriteLine("Creating an Asset with this name instead: " + outputAssetName);
    }

    return await client.Assets.CreateOrUpdateAsync(resourceGroupName, accountName, outputAssetName, asset);
}

Een transformatie en een taak maken die video's analyseert

Bij het coderen of verwerken van inhoud in Media Services is het gebruikelijk om de coderingsinstellingen als recept in te stellen. U dient vervolgens een taak in te dienen om het recept toe te passen op een video. Door voor elke nieuwe video nieuwe taken in te dienen, past u dat recept toe op alle video's in de bibliotheek. Een recept in Media Services wordt een transformatie genoemd. Zie voor meer informatie Transformaties en taken. Met het voorbeeld dat wordt beschreven in deze zelfstudie wordt een recept gedefinieerd waarmee de opgegeven video wordt geanalyseerd.

Transformeren

Bij het maken van een nieuw transformatie-exemplaar, moet u opgeven wat u als uitvoer wilt maken. TransformOutput is een vereiste parameter. Elke transformatie-uitvoer bevat een voorinstelling. Voorinstelling bevat stapsgewijze instructies van de video- en/of audioverwerkingen die moeten worden gebruikt voor het genereren van de gewenste TransformOutput. In dit voorbeeld wordt de voorinstelling VideoAnalyzerPreset gebruikt en de taal ('en-US') wordt doorgegeven aan de bijbehorende constructor (new VideoAnalyzerPreset("en-US")). Met deze voorinstelling kunt u meerdere audio- en video-inzichten uit een video extraheren. U kunt de voorinstelling AudioAnalyzerPreset gebruiken als u meerdere audio-inzichten wilt extraheren uit een video.

Bij het maken van een transformatie moet u eerst met de methode Ophalen controleren of er al een bestaat, zoals weergegeven in de code die erop volgt. In Media Services-v3 retourneert de methode Ophalen van entiteiten null als de entiteit (een hoofdlettergevoelige controle van de naam).

private static async Task<Transform> GetOrCreateTransformAsync(IAzureMediaServicesClient client,
    string resourceGroupName,
    string accountName,
    string transformName,
    Preset preset)
{

    bool createTransform = false;
    Transform transform = null;
    try
    {
        // Does a transform already exist with the desired name? Assume that an existing Transform with the desired name
        // also uses the same recipe or Preset for processing content.
        transform = client.Transforms.Get(resourceGroupName, accountName, transformName);
    }
    catch (ErrorResponseException ex) when (ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
    {
        createTransform = true;
    }

    if (createTransform)
    {
        // Start by defining the desired outputs.
        TransformOutput[] outputs = new TransformOutput[]
        {
            new TransformOutput(preset),
        };

        // Create the Transform with the output defined above
        transform = await client.Transforms.CreateOrUpdateAsync(resourceGroupName, accountName, transformName, outputs);
    }

    return transform;
}

Taak

Zoals eerder vermeld, is het transformatie-object het recept en is de taak de werkelijke aanvraag bij Media Services om deze transformatie toe te passen op een bepaalde invoervideo of audio-inhoud. De taak bevat informatie zoals de locatie van de invoervideo en de locatie voor de uitvoer. U kunt de locatie van uw video opgeven met behulp van: HTTPS-URL's, SAS-URL's of activa die zich in uw Media Services-account bevinden.

In dit voorbeeld is de taakinvoer een lokale video.

private static async Task<Job> SubmitJobAsync(IAzureMediaServicesClient client,
    string resourceGroupName,
    string accountName,
    string transformName,
    string jobName,
    JobInput jobInput,
    string outputAssetName)
{
    JobOutput[] jobOutputs =
    {
        new JobOutputAsset(outputAssetName),
    };

    // In this example, we are assuming that the job name is unique.
    //
    // If you already have a job with the desired name, use the Jobs.Get method
    // to get the existing job. In Media Services v3, Get methods on entities returns null 
    // if the entity doesn't exist (a case-insensitive check on the name).
    Job job = await client.Jobs.CreateAsync(
        resourceGroupName,
        accountName,
        transformName,
        jobName,
        new Job
        {
            Input = jobInput,
            Outputs = jobOutputs,
        });

    return job;
}

Wacht tot de taak is voltooid

Het duurt even voordat de taak is voltooid. Wanneer dit is gebeurd, wilt u daarover een melding ontvangen. U kunt op verschillende manieren een melding ontvangen over de voltooiing van de taak. De eenvoudigste optie (die hier wordt getoond) is het gebruik van polling.

Navragen is geen aanbevolen best practice voor productie-apps vanwege mogelijke latentie. Polling kan worden beperkt bij een te intensief gebruik op een account. Ontwikkelaars moeten in plaats daarvan Event Grid gebruiken.

Event Grid is ontworpen voor hoge beschikbaarheid, consistente prestaties en dynamisch schalen. Met Event Grid kunnen uw apps luisteren naar en reageren op gebeurtenissen uit vrijwel alle Azure-services, evenals aangepaste bronnen. Eenvoudige, op HTTP gebaseerde reactieve gebeurtenisafhandeling maakt het mogelijk om efficiënte oplossingen te bouwen met intelligente filtering en routering van gebeurtenissen. Zie Gebeurtenissen routeren naar een aangepast webeindpunt voor meer informatie.

De taak doorloopt meestal de volgende statussen: Gepland, In de wachtrij geplaatst, Verwerken, Voltooid (de eindstatus). Als bij de taak een fout is opgetreden, krijgt u de status Fout. Als de taak wordt geannuleerd, krijgt u de melding Wordt geannuleerd en vervolgens Geannuleerd wanneer het annuleren is voltooid.

private static async Task<Job> WaitForJobToFinishAsync(IAzureMediaServicesClient client,
    string resourceGroupName,
    string accountName,
    string transformName,
    string jobName)
{
    const int SleepIntervalMs = 20 * 1000;

    Job job;
    do
    {
        job = await client.Jobs.GetAsync(resourceGroupName, accountName, transformName, jobName);

        Console.WriteLine($"Job is '{job.State}'.");
        for (int i = 0; i < job.Outputs.Count; i++)
        {
            JobOutput output = job.Outputs[i];
            Console.Write($"\tJobOutput[{i}] is '{output.State}'.");
            if (output.State == JobState.Processing)
            {
                Console.Write($"  Progress (%): '{output.Progress}'.");
            }

            Console.WriteLine();
        }

        if (job.State != JobState.Finished && job.State != JobState.Error && job.State != JobState.Canceled)
        {
            await Task.Delay(SleepIntervalMs);
        }
    }
    while (job.State != JobState.Finished && job.State != JobState.Error && job.State != JobState.Canceled);

    return job;
}

Foutcodes in taak

Zie Foutcodes.

Het resultaat van de taak downloaden

Met de volgende functie worden de resultaten van de uitvoerasset gedownload naar de uitvoermap, zodat u de resultaten van de taak kunt bekijken.

private static async Task DownloadOutputAssetAsync(
    IAzureMediaServicesClient client,
    string resourceGroup,
    string accountName,
    string assetName,
    string outputFolderName)
{
    if (!Directory.Exists(outputFolderName))
    {
        Directory.CreateDirectory(outputFolderName);
    }

    AssetContainerSas assetContainerSas = await client.Assets.ListContainerSasAsync(
        resourceGroup,
        accountName,
        assetName,
        permissions: AssetContainerPermission.Read,
        expiryTime: DateTime.UtcNow.AddHours(1).ToUniversalTime());

    Uri containerSasUrl = new Uri(assetContainerSas.AssetContainerSasUrls.FirstOrDefault());
    BlobContainerClient container = new BlobContainerClient(containerSasUrl);

    string directory = Path.Combine(outputFolderName, assetName);
    Directory.CreateDirectory(directory);

    Console.WriteLine($"Downloading output results to '{directory}'...");

    string continuationToken = null;
    IList<Task> downloadTasks = new List<Task>();

    do
    {
        var resultSegment = container.GetBlobs().AsPages(continuationToken);

        foreach (Azure.Page<BlobItem> blobPage in resultSegment)
        {
            foreach (BlobItem blobItem in blobPage.Values)
            {
                var blobClient = container.GetBlobClient(blobItem.Name);
                string filename = Path.Combine(directory, blobItem.Name);

                downloadTasks.Add(blobClient.DownloadToAsync(filename));
            }
            // Get the continuation token and loop until it is empty.
            continuationToken = blobPage.ContinuationToken;
        }


    } while (continuationToken != "");

    await Task.WhenAll(downloadTasks);

    Console.WriteLine("Download complete.");
}

Resources in uw Media Services-account opschonen

Waarschuwing

Het is belang rijk dat u resources verwijdert als u deze niet meer nodig hebt, omdat u deze niet meer hoeft te factureren.

Over het algemeen moet u alles opschonen, behalve objecten die u van plan bent opnieuw te gebruiken (meestal gebruikt u transformaties opnieuw en behoudt u StreamingLocators). Als u wilt dat uw account na het experiment is opgeschoond, moet u de resources verwijderen die u niet van plan bent opnieuw te gebruiken. Met de volgende code wordt bijvoorbeeld de uitvoerasset verwijderd:

Resources verwijderen met code

private static async Task CleanUpAsync(
   IAzureMediaServicesClient client,
   string resourceGroupName,
   string accountName,
   string transformName,
   string jobName,
   List<string> assetNames,
   string contentKeyPolicyName = null
   )
{
    await client.Jobs.DeleteAsync(resourceGroupName, accountName, transformName, jobName);

    foreach (var assetName in assetNames)
    {
        await client.Assets.DeleteAsync(resourceGroupName, accountName, assetName);
    }

    if (contentKeyPolicyName != null)
    {
        client.ContentKeyPolicies.Delete(resourceGroupName, accountName, contentKeyPolicyName);
    }
}

U kunt ook de CLI gebruiken.

Een resourcegroep verwijderen met de CLI

az group delete --name <your-resource-group-name>

De voorbeeld-app uitvoeren

Druk op Ctrl+F5 om de AnalyzeVideos-app uit te voeren.

Wanneer we het programma uitvoeren, produceert de taak miniaturen voor elk gezicht dat in de video wordt gevonden. Het produceert ook het insights.json-bestand.

De uitvoer controleren

Het uitvoerbestand van het analyseren van video's heet insights.json. Dit bestand bevat informatie over uw video. U vindt de beschrijving van elementen die in het json-bestand zijn gevonden in het artikel Media intelligence.

Multithreading

Waarschuwing

De SDK's van Azure Media Services v3 zijn niet thread-safe. Als u werkt met een app met meerdere threads, moet u per thread een nieuw AzureMediaServicesClient-object genereren.

Volgende stappen